Jim Lynn

Stuff I’ve learned. Stuff I think.

Why can’t I use Linq on a CaptureCollection?

Posted by jimlynn on November 4, 2009

Doing some Regular Expression work, and I wanted to get a simple enumeration of multiple captures in a match group. I tried this:

var caps = from capture in match.Groups[2].Captures select capture.Value;

but Intellisense told me “Could not find an implementation of the query pattern for source type ‘System.Text.RegularExpressions.CaptureCollection’.  ‘Select’ not found.  Consider explicitly specifying the type of the range variable ‘capture’.”

This is because Captures is a specialised collection, not a generic collection, and it doesn’t therefore support IEnumerable<T>. The solution (which I found here) is:

var caps = from capture in pathmatch.Groups[2].Captures.Cast<Capture>() select capture.Value;

adding the Cast to a Capture allows the rest of the Linq query to work.

I love Linq, but just sometimes, it can be a bit impenetrable.


Posted in Silverlight, Software Development | Leave a Comment »

Funky Popups in Silverlight 3

Posted by jimlynn on September 27, 2009

An old post of mine, Funky Popups using Tweener, showed how you could use the Tweener library in SilverlightContrib to make some interesting transitions.

When Silverlight 3 was released, they added these kinds of tweening functions into the core runtime, so it’s probably time to look at how to use them.

In the original code, our storyboard for one of the items looked like this:


<DoubleAnimationUsingKeyFrames
 Storyboard.TargetName="bounceScaleTransform"
 Storyboard.TargetProperty="ScaleX"
 tween:Tween.From="0.6"
 tween:Tween.To="1"
 tween:Tween.Fps="10"
 tween:Tween.TransitionType="EaseOutBounce"
 Duration="0:0:0.5"/>

Here’s how the equivalent using Silverlight 3’s easing functions. One important different is that we’re not forced to use a keyframe animation any more.


<DoubleAnimation
 Storyboard.TargetName="bounce3ScaleTransform"
 Storyboard.TargetProperty="ScaleX"
 From="0.6"
 To="1"
 Duration="0:0:0.5">
 <DoubleAnimation.EasingFunction>
 <BounceEase EasingMode="EaseOut" Bounces="1" Bounciness="4"/>
 </DoubleAnimation.EasingFunction>
 </DoubleAnimation>

In place of the tweener attributes is the EasingFunction which can be one of several kinds. To simulate the old bounce behaviour we've used a BounceEase function and set EaseOut for the easing mode. The attributes Bounces and Bounciness can adjust the amount of bounce. These values get close to the Tweener behaviour and are fine for our behaviour.

The Swish animation can be similarly replaced by BounceEase animations.

The updated project can be downloaded from here.

Posted in Silverlight, Software Development | Tagged: | 1 Comment »

Scale other content on top of a Deep Zoom Image

Posted by jimlynn on September 17, 2009

Marthinus asked, in a comment:

“is there ANY way to overwrite this, so that I can make the msi use a multiscalesubimage WITH an extra canvas ontop (which would then move and scale WITH the subimage)?”

Now, I’ve never done overlays with collections and sub-images, and one thing you definitely can’t do is interleave other content with subimages of a deep zoom image (since the MultiScaleImage is a single UI element). But I have done things which have locked an overlay panel to the movement of the MultiScaleImage. Here’s a sample. First, the Xaml.


<UserControl x:Class="DeepZoomCanvas.MainPage"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
 <Grid x:Name="LayoutRoot">
 <MultiScaleImage x:Name="msi" Source="http://www.uslot.com/ClientBin/dzc_output.xml"/>
 <Grid
 IsHitTestVisible="False"
 x:Name="overlay">
 <Grid.RenderTransform>
 <TransformGroup>
 <ScaleTransform x:Name="overlayScale"/>
 <TranslateTransform x:Name="overlayTranslate"/>
 </TransformGroup>
 </Grid.RenderTransform>
 <Border
 CornerRadius="8"
 Background="#44FFFFFF"
 VerticalAlignment="Center"
 HorizontalAlignment="Center"
 Padding="30">
 <StackPanel>
 <TextBlock
 FontFamily="Arial"
 FontSize="24"
 MaxWidth="400"
 FontWeight="Bold"
 TextWrapping="Wrap">
 This shows some elements which
 scale and translate locked to
 the underlying MultiScaleImage.
 Any layout items can be used here.
 </TextBlock>
 <Border Background="#55FF0000" Padding="10" HorizontalAlignment="Center" VerticalAlignment="Top">
 <StackPanel>
 <TextBlock
 FontFamily="Arial"
 FontSize="0.1"
 >This is a tiny line of text which still scales in concert with the deep zoom image.</TextBlock>
 </StackPanel>
 </Border>
 </StackPanel>
 </Border>
 </Grid>
 </Grid>
</UserControl>

And the corresponding C# code:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace DeepZoomCanvas
{
 public partial class MainPage : UserControl
 {
 public MainPage()
 {
 InitializeComponent();
 msi.MouseLeftButtonDown += new MouseButtonEventHandler(msi_MouseLeftButtonDown);
 msi.MouseMove += new MouseEventHandler(msi_MouseMove);
 msi.MouseLeftButtonUp += new MouseButtonEventHandler(msi_MouseLeftButtonUp);
 msi.MouseWheel += new MouseWheelEventHandler(msi_MouseWheel);

 // Track changes to the multi scale image
 msi.ViewportChanged += new RoutedEventHandler(msi_ViewportChanged);
 }

 /// <summary>
 /// This is the code which locks the overlay to the underlying deep zoom image.
 /// All it really does is set the scale factor and offset of the overlay
 /// based on the current setting of the deep zoom image.
 /// </summary>
 ///
<param name="sender">event sender</param>
 ///
<param name="e">event args</param>
 void msi_ViewportChanged(object sender, RoutedEventArgs e)
 {
 // This event is called during animations of the image.
 // Match the scaling of the canvas with the image
 Point viewportOrigin = msi.ViewportOrigin;
 double viewportWidth = msi.ViewportWidth;

 // The scale factor is just the inverse of the ViewportWidth
 overlayScale.ScaleX = 1 / viewportWidth;
 overlayScale.ScaleY = 1 / viewportWidth;

 // The offset is calculated by finding the location of the origin of the dzi
 // in element coordinates.
 Point newO = LogicalToElement(new Point(), viewportOrigin, viewportWidth);
 overlayTranslate.X = newO.X;
 overlayTranslate.Y = newO.Y;
 }

 private Point LogicalToElement(Point p, Point Origin, double Width)
 {
 return new Point(((p.X - Origin.X) / Width) * msi.ActualWidth,
 ((p.Y - Origin.Y) / Width) * msi.ActualWidth);
 }

 public Point ElementToLogical(Point p, Point Origin, double Width)
 {
 return new Point(Origin.X + (p.X * Width) / msi.ActualWidth,
 Origin.Y + (p.Y * Width) / msi.ActualWidth);
 }

#region Mouse handling
 void msi_MouseWheel(object sender, MouseWheelEventArgs e)
 {
 if (e.Delta < 0)
 {
 Point logicalPoint = msi.ElementToLogicalPoint(lastMousePos);
 msi.ZoomAboutLogicalPoint(0.8, logicalPoint.X, logicalPoint.Y);

 }
 else
 {
 Point logicalPoint = msi.ElementToLogicalPoint(lastMousePos);
 msi.ZoomAboutLogicalPoint(1.2, logicalPoint.X, logicalPoint.Y);
 }
 }

 void msi_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
 {
 if (IsMouseDown)
 {
 msi.ReleaseMouseCapture();
 if (IsDrag == false)
 {
 if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
 {
 Point logicalPoint = msi.ElementToLogicalPoint(lastMousePos);
 msi.ZoomAboutLogicalPoint(0.8, logicalPoint.X, logicalPoint.Y);
 }
 else
 {
 Point logicalPoint = msi.ElementToLogicalPoint(lastMousePos);
 msi.ZoomAboutLogicalPoint(1.2, logicalPoint.X, logicalPoint.Y);
 }
 }
 IsMouseDown = false;
 IsDrag = false;
 }
 }

 void msi_MouseMove(object sender, MouseEventArgs e)
 {
 lastMousePos = e.GetPosition(msi);
 if (IsMouseDown)
 {
 IsDrag = true;
 }
 if (IsDrag)
 {
 Point newPoint = lastMouseViewPort;
 newPoint.X += (lastMouseDownPos.X - lastMousePos.X) / msi.ActualWidth * msi.ViewportWidth;
 newPoint.Y += (lastMouseDownPos.Y - lastMousePos.Y) / msi.ActualWidth * msi.ViewportWidth;
 msi.ViewportOrigin = newPoint;
 }
 }

 bool IsMouseDown = false;
 bool IsDrag = false;
 private Point lastMouseDownPos = new Point();
 private Point lastMouseViewPort = new Point();
 private Point lastMousePos = new Point();

 void msi_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 {
 IsMouseDown = true;
 msi.CaptureMouse();
 lastMouseDownPos = e.GetPosition(msi);
 lastMouseViewPort = msi.ViewportOrigin;
 }

 #endregion    
 }
}

All the work is done in the ViewportChanged event handler (which fires every time the viewport changes, even during animations). I’ve set a scale transform and a translate transform on the grid (which could be a canvas if you want) and we adjust the scale and translate values to match the underlying image.

All the rest of the code is just bog-standard deep zoom image mouse handling.

Try zooming into the red square to see a very small line of text.

Hope this helps.

Posted in Deep Zoom, Silverlight, Software Development | Leave a Comment »

Why I Love Derren Brown

Posted by jimlynn on September 12, 2009

This week, Derren Brown predicted the lottery numbers.

Well, that’s what he said he was going to do, and that’s what he presented. He showed a set of six balls, kept them in full view throughout the live lottery broadcast, then revealed that the numbers on the other side of the balls were the winning numbers. Then he said his show on Friday would show how he did it.

Following the ‘revelation’ a lot of people are disappointed. They genuinely believed he would reveal the technique he used.

Strangely, they’re disappointed because they’ve believed everything he’s ever said previously, when the only thing they should actually believe is his standard ‘disclaimer’: That he uses ‘magic, suggestion, psychology, misdirection and showmanship’.

The prediction was a traditional mentalist prediction in every form. The performer has a ‘prediction’ which he places somewhere he can’t tamper with it, the event happens, then the performer reveals his prediction. This has been the form of this trick for decades.

I don’t think I’m revealing any deep secrets when I say that it’s impossible to guess the numbers, and almost impossible to accurately rig a lottery machine. So if you discount those possibilities, all that’s left is how to get the numbers onto the balls after they’ve come up on the broadcast. There are several ways this could have been done, ranging from an enormously complex split screen camera effect (which I doubt because it would break Derren’s ‘rules’) to electronic balls, laser etching, projection or (my theory) a hidden printing mechanism under the balls.

But how he did the actual trick isn’t really important. It was a perfectly performed illusion, and got a lot of people watching. Which is good, I think.

But the ‘revelation’ on Friday was problematic for me. I was fairly sure he wouldn’t go anywhere near the actual technique (because, frankly, magical techniques are clever, but ultimately mundane, compared to the effect they have). So how would he fill an hour while a) not talking about how he did it, and b) not outright lying.

I have a lot of respect for Derren. I think he’s one of the good guys. His book, Tricks of the Mind, was a fascinating look at mind, belief, memory and ended up almost as a fluffier version of Dawkins’ ‘The God Delusion’. And he’s never claimed to have (or believe in) psychic powers, even when presenting effects that seem to require them.

In ‘The System’ he appeared to be saying that it was possible to predict horse races, but the revelation was actually satisfying (topped off by a genuine magic trick). In one of his Tricks of the Mind he appeared to have hypnotised someone into being able to play piano like a virtuoso. I grew more and more uncomfortable with that show, as I knew it was impossible, but the revelation at the end actually moved me to tears.

I have an expectation that Derren will ‘play fair’ with the audience. Within the context of a magical performance, that is, where you expect the performer to declare that he’s doing something that appears impossible.

So I do get uncomfortable when he starts talking about the PEAR experiments. These were experiments performed (in part) to detect psychokinesis, the ability to affect the random behaviour of a machine using the mind. They initially said they were successful, but later analyses showed that their results weren’t as good as they suggested.

Derren then showed a nice trick with coin tossing that appeared to show an effect, but then explained it was a maths trick. Then, significantly, he said something like ‘and it turned out that the PEAR results didn’t really stand up’. Now, he said that casually, almost throwaway, so most of the audience probably didn’t really notice, so the strong suggestion that it’s possible to affect things with the mind remained, but he did that while still telling the truth about the experiments. That pleased me a lot.

Then came the main part of the programme, where he had a group of people harnessing ‘the wisdom of crowds’ to predict the lottery numbers. I’ve got an idea how this was done, but it’s enough to say this was another trick. But basically, this was just another piece of misdirection.

Then, just as you think he’s saying that’s how he did it, he did a very funny description of how he might have fixed the lottery machine.

And right at the end, with an almost straight face, he said ‘So I couldn’t possibly admit that I fixed the machine – which I didn’t – so now, when people ask me how I did it, I’ll just say “It was a trick”.’

Perfect. He managed a whole hour of fun and misdirection, and yet he genuinely did say how he did it.

And that’s why I love Derren Brown.

Posted in Uncategorized | Tagged: , , | Leave a Comment »

Why don’t I get MouseUp events in the Bing Maps Silverlight Component

Posted by jimlynn on September 8, 2009

The Bing Maps Silverlight component (currently in CTP) allows you to overlay items on the map, but it does some odd things to mouse events. Take the following Xaml:


<UserControl x:Class="BingBlogPost.MainPage"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 xmlns:map="clr-namespace:Microsoft.VirtualEarth.MapControl;assembly=Microsoft.VirtualEarth.MapControl"
 mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
 <Grid x:Name="LayoutRoot">
 <map:Map>
 <Border Padding="8"
 Background="Gray"
 HorizontalAlignment="Center"
 VerticalAlignment="Center"
 MouseLeftButtonUp="Message_Click"
 >
 <TextBlock Text="Click here"/>
 </Border>
 </map:Map>
 </Grid>
</UserControl>

This will show the world map, with our ‘control’ in the centre. Now, mouse handling is interesting using the map component. You’ll notice that if you click and drag on the control, the map underneath will drag. In this example we’ve got an event handler which is set to receive the button up event (to simulate a mouse click). here’s the event handling code:

private void Message_Click(object sender, MouseButtonEventArgs e)
{
     MessageBox.Show(“Clicked!”);
}

But you’ll notice that this event doesn’t fire on a single click. Oddly, it does fire after a double-click. So clearly, the map itself is doing something tricky with events.

If you want to get a click event, there’s two things you can do. You could put in an actual button. This handles mouse events properly and will pass on its own Click event as you’d expect. But if you want to roll your own, there’s a simple trick: add a handler on the control for MouseLeftButtonDown and handle it with this code:

private void Message_MouseDown(object sender, MouseButtonEventArgs e)
{
     e.Handled = true;
}

This is enough to stop the map eating the mouse down event and capturing the mouse (which is why you never get the event). You’ll get the Up event as you expect and you can handle it normally.

Posted in Silverlight, Software Development | Tagged: , | Leave a Comment »

Windows 7 Media Center on Acer Aspire Idea 500

Posted by jimlynn on August 28, 2009

We had a catastrophe recently. Our Windows Vista media centre developed a puzzling problem. It refused to boot up, complaining of no boot disc. But if I went into the BIOS and put the SATA boot drive back to the top of the boot drive order and reboot, it would boot up fine.

For a while.

Then, it started randomly hanging, then restarting, and giving the ‘No boot disk’ error again. Until it got to the point where it wouldn’t get through the boot sequence before rebooting.

Clearly, it was unhappy.

I’ve had hardware issues before.

The PSU has failed twice, in exactly the same way, in the last two years. Others have reported the same symptoms, so there’s definitely some problem, and a replacement PSU has solved it both times.

This is different, though. It looked like a faulty drive, although this drive was new this year.

Whatever the reason, we were without TV. We don’t watch live TV. All our TV viewing is through the Media Centre. Or iPlayer (mostly the kids use iPlayer on their netbooks when they don’t want to watch what’s on the big telly).

So I clearly had to do something.

I decided to put a new drive in. I had a spare 500G SATA drive with some archived TV, so I cleared all that off onto the 1.5TB external (which is now getting full itself) and put it into the Acer.

Then I booted up with the Win7 RC in the drive.

About 30 minutes later, Win7 was running. All was not rosy, though.

Windows 7 issues with Acer Aspire iDea 500

A default install was missing some drivers. I was using a TV as a monitor (easier to do where the machine lives) and the output was black and white and quite fuzzy – clearly NTSC rather than PAL. And there was no sound coming through the TV speakers, despite Win7 thinking a sound driver was working. And Device Manager was telling me that the TV Tuner card was unrecognised (not surprising – it’s an obscure OEM device from Yuan).

Luckily, I had two things on my side: Windows 7 uses the same driver model as Vista; and I’d gone through a complete install of Vista on this machine (it originally came with XP Media Center Edition) and I’d made sure I collected all the drivers I’d had to install to get things working. I’d even burned them onto DVD and remembered where I’d stored the DVD. Most unlike me, I have to admit.

So I grabbed the driver disk and installed away.

Graphics

The machine has an Intel 945GM integrated graphics chipset. I installed the drivers from my DVD, but it didn’t make much difference. The Intel drivers have a pig-ugly custom configuration control panel which allows you to set things like the TV mode, and I’d already set the mode to PAL_I, but I tried again, and this time, after a reboot, the colour image reappeared. I’ll come back to the graphics driver, but for now, that was OK.

Sound

No sound from the TV output (through a scart socket). I remembered having a similar issue with Vista, so I installed the Realtek drivers, and the sound was restored. (I had a plan B – a small USB speaker – but I’m glad I don’t have to use that plan.)

TV Tuner and Media Centre

I installed the Yuan drivers I’d used for Vista, and Device Manager showed that it believed they were correct, so to test it, it was time to start Media Centre for the first time.

Media Centre installation in Windows 7 was a little quicker than Vista. It seemed to ask fewer questions, and it recognised my tuner (it’s a dual digital/analogue tuner and both channels were recognised). I chose the default settings, and the only question it asked was my postcode, for the tuning and guide data.

After the requisite 15 minutes of searching for channels, it found around 91, which might even be more than I’d got before (the number of available channels tends to change, so that’s not perhaps surprising).

Then it started for real. I checked the guide, and started watching BBC One. After the usual tension-filled 5 seconds while it detects the signal, it started playing perfectly. Fantastic!

First Impressions

Media Centre strikes me as an unloved project. It could easily be a key selling point for Windows. other platforms’ alternatives are nowhere near as polished. And yet, it doesn’t seem, from the outside, that the project gets much development attention. Windows 7 MC still looks a lot like Vista. Some screens are almost identical. As such, the differences are often small, but telling.

Guide

The guide has been slightly redesigned. The grid is flatter in design, but doesn’t really show any more information. And some navigation features are missing. When you click on the channel name, it switches to the channel specific display, showing more upcoming shows. In Vista, Left and Right would cycle through the channels. In Win7 this doesn’t work. I used to use this all the time, so its absence is annoying.

Clicking on a specific programme in the channel listing brings up a very different Programme Info page. It still has the key options for recording the show, although the buttons are redesigned, and much smaller. This seems an odd choice, and on the tiny 14in screen I was using, it’s not that clear. However, I understand that they’re probably targeting much larger screens, so it’s probably unfair to complain.

One definite gripe, though is the behaviour when recording shows. I occasionally like to scroll through the channel listings and marking upcoming shows to record. In Vista, this was a couple of clicks. One click to bring up programme properties. Another click to record. and you’d be back where you were.

In Windows 7 it’s slightly different. When you click the Record button, you’re taken back to the channel listing, but the focus is on the button to the left of the listings, rather than on the show you were recording. This makes it a lot more difficult to just scroll through recording shows.

There is a shortcut, though, and I’m not sure if this worked in Vista. If you hit the Record button once, it will set the programme to record. Hit it again, and it sets it to record the series. Hit it a third time and it cancels the recording. This is nice, and if I remember it, it will be even quicker than before.

Live TV

There are two apparent improvements here (at least, to me). Firstly, I was surprised to see a ‘press the red button’ logo appearing. So I did, and I got the BBC’s interactive text service. I’ve never seen this on Vista, so I think it’s new in Windows 7. Nice to have, although it’s not a service I make use of myself. Sadly, they don’t record the stream, so the red button isn’t available on recordings. That might have been cool.

Another addition, which might only be new for the UK, is subtitles. These are available on the newly expanded ‘info’ menu which now opens a bar across the bottom of the screen and has several sections. I haven’t checked whether the subtitles are recorded – I presume they are. Old recordings from Vista MCE do not have subtitles.

Another tiny improvement: On Vista and XP, when recording BBC TV, there was always a recording glitch just as the programme was about to start. I’m not sure what that was, but it was ever-present. All my recordings have a slight glitch about 5 seconds after the channel ident starts. It’s probably something particular in the transport stream that the recording was choking on. But it’s gone in Windows 7 (well, on the programme I just checked).

Recorded TV

This is where we spend most of our time, and it’s never been a perfect environment in Vista.

I have some archived TV. Quite a lot of it.

Not sure how much, but over 5 terabytes of it, spread across lots of external drives.

Vista had… issues with this.

Vista has a nice feature – More TV folders – which allows the Recorded TV page to get files from more than one directory – something XP couldn’t do.

But Vista had performance issues. The more files and folders you added, the more time it would take to open Recorded TV. It got to be almost a minute before the screen would appear. I had to remove rarely used folders because it was so interminable. Every Time I’d go to the root Recorded TV page, it would spend >30s doing something before it would show us the page. It was quite bad. I’d almost have time to make tea while waiting.

Naturally, I was keen to see if Windows 7 had addressed this issue. I wasn’t hopeful, as I’ve never seen this issue mentioned as a problem with Media Centre. I plugged in two or three of my larger hard drives, and told Media Centre to monitor all the folders containing TV. Then I hit Recorded TV.

There was a pause. But not a long one. Recorded TV appeared. It didn’t yet have all the files, but it was up and showing me what it had.

I left it a while, indexing. Then I tried again. Again, there was a pause, a little longer, but still acceptable. Three seconds or so.

It’s also pretty-much instant going into groups of programmes when sort by title is on, and instant again going back up to recorded TV. Vista would have its long pause every time I went to the Recorded TV root. Windows 7 just seems to snap back.

I’m very happy with this improvement.

Playback

There’s one issue I haven’t sorted out. Playback of old recorded TV (recorded in Vista) judders. Every couple of seconds, the picture pauses then quickly catches up with itself. The sound is fine. At first, I thought it was a video driver issue, with the driver not being able to keep up with playback. But Live TV was smooth, and playback of a newly recorded progranne also looks smooth.

I know that they’ve moved to a new file format, so the old dvr-ms format is now a legacy format, but it’s all MPEG2 in the end, so I’m at a loss what the problem could be. Also, I know I’ve played back dvr-ms files on other Windows 7 machines, and not noticed such issues. I watched ‘Who Framed Roger Rabbit’ on a projector, played from a Samsung netbook, and it was fine, so it’s hard to know what the issue might be.

Conclusion

I’ve held off from going to Windows 7 on the media centre until now on the basis that it basically worked, and was in use every day. An upgrade or rebuild always takes time and might not even work, so I didn’t want to do it on a whim. So in a way, the machine’s problems were a good thing.

Windows 7 installation was quick and easy. My preparation of a driver disk paid off, and all the drivers I needed worked. I was worried about the tuner card, as I know that some very popular cards have had issues with Windows 7, but mine works fine.

The performance improvements in Recorded TV will make a huge difference.

And I hope I can get to the bottom of the skipping on old recorded programmes. It’s going to bug me otherwise.

I’ve yet to look at the extender features. I’d like to be able to access recordings across the network on any PC, but I haven’t set up a homegroup yet. I’ll also try once more to set up my XBox as an extender, something I was unable to get working on Vista.

To sum up. Windows 7 Media Centre is worth the upgrade, if your hardware works. It’s still the same Media Centre, just better.

Update: 29 August 2009

At the same time as the Vista media centre dies, our TV died. Sort of. The switch on the front broke, and would no longer lock on. It’s a 6 year old 32in CRT TV that’s frankly showing its age, so I’ve been expecting it to die at some point. It was a bit of a coincidence it broke the same day as the MC, but that switch has been dodgy for a while. It’s funny how these things happen together, though.

So I wasn’t too upset that we needed to buy a new TV. Which we did today. We bought a Samsung 40in LCD TV. Something like this one. I toyed with buying a 50in plasma, but it was an extra £220, and 40in is still significantly bigger than our current TV, and probably as big as we want. It fits in the space where the old TV was, in the corner of the room, and we’ll probably put it on the wall eventually.

But how does it get on with my fairly old Media Centre? I was worried that it wouldn’t drive the HD resolution screen fast enough, that it would be choppy or slow.

I needn’t have worried.

I rebooted the Media centre, plugged in the HDMI cable, selected the right input on the TV and waited.

I’ve never been so pleased to see the ‘Starting Windows’ screen.

It detected the TV’s resolution (1920×1080) and I had a perfectly working display.

Except there was no sound.

After much fiddling and swapping, I’ve concluded that the HDMI cable I bought doesn’t carry sound. Probably. I’d have to try it with another known, working TV/Device combination to be sure.

Luckily, the TV has an input that takes this possibility into account (for DVI, VGA or video-only HDMI inputs) and I ran an extra audio cable to the TV and finally got sound.

And because it’s now using a native widescreen mode (instead of the square mode I was forced to use with a standard def TV) it now switches from widescreen to 4:3 when necessary. No longer does Jon Stewart look tubby.

And the best result by a long way is that playback of old recordings are no longer stuttering. They’re as smooth as they used to be on Vista.

So my new conclusion: Windows 7 Media Centre, plus an HD TV is made of win. I’m very, very happy.

Posted in Uncategorized | Tagged: , | 8 Comments »

Isobel’s First Movie

Posted by jimlynn on July 19, 2009

We gave Isobel a Flip video camera for her birthday, and she’s had fun filming loads of stuff. Yesterday we sat down to edit her first movie. Here it is.

Its production adheres to the strict principles of the Flipme movement:

  1. It must be shot on a Flip or similar flash-based camera
  2. Each scene must be shot in order
  3. It must be shot on found locations. Or sets made of cardboard boxes and glitter glue.
  4. All performers must be plastic dolls. Or Lego.
  5. Optical work and filters are forbidden. Because they’re hard to do with a Flip.
  6. The film must only contain superficial action. (Introspection or social realism, etc. must not occur)
  7. Genre movies are encouraged. Because they’re better.
  8. The director must do all the dialogue live. Or her brothers and sisters if they won’t stop bugging her.
  9. The only allowable post-production is the straight assembly of the filmed scenes in the Flip software, in order.
  10. The director gets the only credit.

I think this movement could take off.

Posted in Uncategorized | Tagged: , , | Leave a Comment »

A Deep Zoom celebration

Posted by jimlynn on July 4, 2009

The novelist Neil Gaiman had a virtual party when he passed 666,666 followers on Twitter. He asked people to send pictures of themselves with balloons, and had a mosaic made (he mentions it here).

I thought the picture would make a good Deep Zoom image, so I made one.

Posted in Uncategorized | Leave a Comment »

Something non-tech related

Posted by jimlynn on May 24, 2009

I recently found the following picture on my daughter’s bedroom wall.

Wolves in the Walls

Wolves in the Walls

I’d recently read the children Neil Gaiman’s Wolves in the Walls and Isobel was obviously inspired (If you you don’t know the story, it says ‘When the wolves come out of the walls, it’s all over’). So I posted on Twitter to Neil Himself. Now Neil Gaiman has over 400,000 followers, so I was quite surprised when he retweeted it.

It’s interesting to see how powerful twitter is – I had about ten new people follow me right after this, and his message was itself retweeted about 20 times (with some nice added comments, I thought).

And just when I thought my fatherly pride couldn’t increase, he mentioned it on his blog, too.

I think that this amateur Wolves In the Walls fanart is my favourite photograph of recent vintage though.

In a way, it’s similar to getting your picture printed in a favourite comic. Except, of course, it’s way awesomer because it’s Neil ‘Scary-Trousers‘ Gaiman!

Posted in Uncategorized | Tagged: , | Leave a Comment »

Wrangling very large Deep Zoom images

Posted by jimlynn on February 12, 2009

My current project features a large Deep Zoom image. Very large. About 123 Gigapixels, in fact. Here’s the raw numbers:

  • 20 tile levels (0-19)
  • about 20GB of jpeg images
  • about 2.5 million tiles
  • almost 1.9 million tiles just in the highest level of zoom

First of all, what’s impressive is that Silverlight doesn’t even break a sweat with this image. Deep Zoom is designed such that it almost doesn’t matter how big the raw image is, it only matters how many pixels you’ve got on your screen, because it will always show you the resolution and section of the picture that you want. The main constraint is how fast you can serve (and download) the tiles.

But such a large image and tile set brings some interesting problems, and I wanted to post a bit about some of the issues we’ve found, and how we’ve addressed them.

Lots of files in one place are bad

Although not cripplingly so…

As mentioned earlier, our top level of tiles (the native resolution level) contained almost 1.9 million tiles. This is how Deep Zoom composer arranges its output and how Silverlight’s MultiScaleImage expects to find them. And it still works. Although one thing we learned early on is that FAT32 can’t cope with that number of files. We use removable hard drives for convenience, and I would always forget to reformat them to NTFS, then spend hours trying to build our image, only to fail because it ran out of directory entries. Grr.

But Fat32 aside, serving the images from NTFS on these tiny hard drives was very smooth. It didn’t seem to worry that there were so many files. The problem comes when copying the files, particularly to a network server. The copy would always start out fairly nippy, but when it got to the larger directories, it would just grind to a halt, probably because it was doing a directory enumeration each time over the network. It was definitely slowing down over time.

The solution I decided to use was to rearrange the files. I decided to take the X index of the filename and use that to generate a subdirectory in which to store the file. This would mean that, for example, if I had a file 142_1232.jpg in level 19, it would move from 19\142_1232.jpg to 19\1\4\2\142_1232.jpg. This method means that the maximum number of files in any single directory would now depend on the height of the image, rather than the area – in our specific case limiting us to 1718 files maximum.

Now, this is all very well, but the MultiScaleImage expects the files in their original places, so how do we fix that problem. Two ways would work. The first would be to use URL rewriting on the server side (mod_rewrite on Apache, for example) which would work OK, but we’d need two different solutions depending whether it’s Apache or WIndows serving the files. The second way is to write a custom tile source for MultiScaleImage.

Advantages of a Custom TileSource

The main advantage is that we don’t care where the images are hosted – they remain just files in a directory structure, and can be served fast by the web server. Also, avoiding mod_rewrite etc. might be useful as that’s more work for the servers to do that could be better performed by the client. It also means that the same solution works whether we’re serving locally (for testing) or serving from a dev server (which would be running Apache, probably).

Problems with a Custom TileSource

Although it’s easy enough to inherit from the base MultiScaleTileSource class, they’ve not made it very easy to do exactly what you need to do. I wanted to be able to create a class which had a constructor which took a Uri, and which read from an Xml file to get information about size etc. But this seems to be impossible. MultiScaleTileSource expects you to know already the dimensions of your image when the constructor is called, and doesn’t allow any way to initialise these values after the constructor is called, due to the protection level of other members. And since Silverlight doesn’t have a synchronous way to read from a file, you can’t open the file in the constructor. Annoying.

In the end, I cheated, because I know how big my image is already. I’ve already got code which takes the Uri of the image from the host HTML page, so I adjusted that to take the path to the new files, along with the width and height, as parameters which I can then pass to my new constructor, bypassing the need to read from a file. It’s not ideal, and I hope that this process is opened up a little in future.

Once I’d arrived at this way of initialising my class, writing the override method to return the tile paths was a little easier, although again I had to hard-code some specific information about my particular image – My image has a virtual square shape, but is actually rectangular, so there are lots of virtual tiles which don’t actually exist. DeepZoomImageTileSource handles this with the information in the xml file (it’s all part of the ’sparse’ nature of deep zoom images) but I just hard-coded the limits of my tileset.

This solution works well for us. I haven’t tested it to see if it makes a difference with serving the images, but it definitely drastically reduced the time it takes to deploy our images to a server – from something that had already taken days and was slowing down, to something that completed within four hours. So that was a win for us.

I’m not sure how useful this code would be, but I’m including it anyway, for illustration.


public class HashedDeepZoomTileSource : MultiScaleTileSource
{
    private string RootPath;

    public HashedDeepZoomTileSource(string root, int imageWidth, int imageHeight) : base(imageWidth,imageHeight,256,256,1)
    {
        RootPath = root;

    }

    /// <summary>
    /// Constructs a tilesource given a string describing the root of the image
    /// And the image size.
    /// </summary>
    ///<param name="packedRoot">string containing the root directory (relative to XAP file) and the
    /// width and height packed in the following form:
    /// root|width|height
    ///
    /// so an image with a root directory GeneratedImages/uk3_files and width of 232000
    /// and a height of 445000 would have a string:
    ///
    /// GeneratedImages/uk3_files|232000|445000
    ///
    /// If the path is a regular path, then we simply construct a normal DeepZoomImageTileSource.
    /// </param>
    /// <returns>Either A HashedDeepZoomTileSource object or a normal DeepZoomImageTileSource</returns>
    public static MultiScaleTileSource UnpackPath(string packedRoot)
    {
        string[] parts = packedRoot.Split('|');
        int width;
        int height;
        if (parts.Length != 3 || !int.TryParse(parts[1], out width) || !int.TryParse(parts[2], out height))
        {
            return new DeepZoomImageTileSource(new Uri(packedRoot, UriKind.Relative));
        }
        return new HashedDeepZoomTileSource(parts[0], width, height);
    }

    /// <summary>
    /// This is a hack, It (and maxheights) describes the maximum tile ID available
    /// at all the tile heights in the image.
    /// </summary>
    int[] maxwidths =
    {
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        1,
        2,
        4,
        8,
        17,
        34,
        68,
        136,
        273,
        546,
        1093

    };

    int[] maxheights =
    {
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        1,
        3,
        6,
        13,
        26,
        53,
        107,
        214,
        429,
        859,
        1718
    };

    /// <summary>
    /// Overrides the GetTileLayers method to provide a URL for the given tile source.
    /// We have to create a fully qualified domain path - it doesn't like relative
    /// paths.
    /// </summary>
    ///<param name="tileLevel">Which level of tile resolution (0-19 e.g.)</param>
    ///<param name="tilePositionX">X position of required tile</param>
    ///<param name="tilePositionY">Y Position of required tile</param>
    ///<param name="tileImageLayerSources">List to populate with Uris pointing at the tiles they want</param>
    protected override void GetTileLayers(int tileLevel, int tilePositionX, int tilePositionY, System.Collections.Generic.IList<object> tileImageLayerSources)
    {
        if (tileLevel >= 0)
        {
            // MASSIVE KLUDGE
            // Since our map is 'sparse' in that its logical size if 480000 square
            // but we only have tiles for a width of 280000 so we have to not return
            // non-existent URLs.
            // We look up the maximum X position value from the maxwidths

            if (tilePositionX <= maxwidths[tileLevel] && tilePositionY <= maxheights[tileLevel])
            {
                StringBuilder path = new StringBuilder(RootPath);
                if (RootPath.EndsWith("/") == false)
                {
                    path.Append("/");
                }
                path.AppendFormat("{0}/", tileLevel);
                foreach (char digit in tilePositionX.ToString().ToCharArray())
                {
                    path.AppendFormat("{0}/", digit);
                }
                path.AppendFormat("{0}_{1}.jpg", tilePositionX, tilePositionY);
                string s = App.Current.Host.Source.ToString();
                s = s.Substring(0, s.LastIndexOf('/') + 1);
                tileImageLayerSources.Add(new Uri(s + path.ToString(), UriKind.Absolute));
            }
        }
    }
}

Posted in Deep Zoom, Silverlight, Software Development, Uncategorized | 7 Comments »