Welcome to WindowsClient.net | Sign in | Join

photoSuru Application Content

The subscription file is the root of all of photoSuru’s content abilities. It describes where to look for feeds describing the content photoSuru should download, when it should download it, and what theme photoSuru should use to display it. Once you know how data moves through photoSuru, we’ll describe how you can create your own subscriptions – using our tools or your own process – and how they can be used to get your content into your application.

photoSuru Data Flow

Everything photoSuru displays starts off somewhere – as a file, on a camera, or even in a database of some sort. That doesn’t matter to photoSuru; all it needs to know is a web address where it can download the file. This can be a direct location to the file – say, http://someurl.com/file.jpg – or it can even be an online service so long as it can be accessed with a simple HTTP GET, for example, http://someurl.com/GetImage.svc?Image=492. Images requiring basic or form authentication work too; Subscription Center will simply prompt for a set of credentials before it is able to download the content.

If you’re grabbing images from a database, you’ll want to write a service that provides these images to requesters over standard HTTP GET calls. If you’re using WCF, that means setting the [WebGet] attribute on your services.

Once you’ve located your content and have suitably exposed it to the web, you’ll have to build a feed so that photoSuru knows how to understand your content – what goes into each album and gallery, what things have been updated, etc.

Inside photoSuru, a set of photos is called an Album. This album can contains its own name and description, separate from the photos it contains, and allows users of photoSuru to quickly find the content they are looking for by switching between albums. For example, you may construct an album for each event you have photos for, or each date or month that photos were taken. Both a few photos and a large number of photos are supported in an album, but both extremes make using the application more difficult; with many photos in an album, it’s hard to find the ones you want quickly; with only a few, it’s hard to find the photos you want amongst dozens of albums. We’ve found that organizing photos around a single concept – their content, the date they were taken, or something similar – works best.

Each set of albums rolls up into a gallery. A gallery is the maximum amount of photos a user would ever be presented at once, and forms an isolated photo experience. You might choose to wrap all of your photos for an entire year in a gallery, or maybe you want to separate out all of your black-and-white photos across multiple albums and galleries into their own gallery. Or you may choose to place all of your photos in a single gallery; the sample photo feed and this feed both only have a single gallery (you can switch between galleries using the breadcrumb bar).

Once you’ve decided how to structure your photos for display in photoSuru, it’s time to write down that information in a form that photoSuru understands; that form is RSS feeds. photoSuru (and all SCE applications) use simple RSS feeds with several extensions. These RSS feeds are nested – a Content Feed contains items for each Gallery Feed, each Gallery Feed contains items for each of its Album Feeds, and the Album Feeds are a traditional flat Media RSS feed with photos as their items.

While vanilla RSS readers can read SCE RSS feeds for vanilla RSS content (item, link, etc), only CSX-aware feed readers can leverage the extensions and "understand" how these feeds relate to each other, and how to follow embedded feed links. Feeds are not nested past the album feed level.

Each RSS feed contains the metadata associated with a particular item in photoSuru – whether it be a gallery, album or photo. The richest metadata occurs with photos, so we’ll describe each element of an album feed’s item definition describing a photo:

  • <guid/>: A unique identifier for the photo
  • <link/>: A link to the photo, or to something related to the photo. Pressing ‘B’ in photoSuru will launch this link.
  • <title/>: The photo’s title, displayed beneath the photo
  • <description/>: A short description of the photo which gets overlayed on top of the photo when it is displayed and descriptions are turned on
  • <pubDate/>: The date the photo was published last
  • <csx:lastBuildDate>: The last time the item changed. When this changes, Subscription Center downloads a new version of the file.
  • <csx:link>: An item – any item – that should be downloaded and cached by Subscription Center
  • <csx:link nestedFeed="False" descriptionFile="True"/>: A long description text file that should be downloaded along with the photo.
  • <media:content/>: The photo to display
  • <media:thumbnail/>: The photo’s thumbnail, optimally 100px on the shortest side.
  • <media:category/>: A space-delimited set of tags

For each album of photos you want to show, you’ll need to build an Album Feed containing photo items; for each set of albums, you’ll need to build a Gallery Feed containing items for the Album Feeds (set nestedFeed="true" on the <csx:link/> element), and then you’ll need to build one Content Feed containing items for all of your Gallery feeds. Since that is a rather involved procedure, we’ve created a set of classes you can use to build these files easily. Using the classes in the ScePhotoFeed namespace, you would create a feed by creating a SceSyndicationFeed object, and then adding items to it:

  • To make a Content Feed, add GalleryFeedItems
  • To make a Gallery Feed, add AlbumFeedItems
  • To make an Album Feed, add PhotoItems

These classes will allow you to build a correctly-formatted feed in an object-oriented fashion, and can be hosted directly through WCF (use the [WebGet] attribute) if you need to generate these feeds on demand.

Alternatively, we’ve wrapped up all of that functionality into the photoSuru Feed Wizard, whose FeedGenerators use these classes to build a set of feeds from files on disk, structured according to the diagram for the previous topic. More details on the wizard appear later.

Once all of the feeds are built, a subscription file is creating describing where to find all of the feeds in that subscription and what application to launch to view them. Subscription Center downloads all of the data so that they can be used offline, and synchronizes periodically.

A subscription file contains:

  • <Name/>: The subscription name
  • <LogoPath/>: The path to the subscription’s logo file
  • <ApplicationTheme/>: If the appliction supports themes, then this is the theme it should use to display content
  • <ApplicationPath/>: The path to the application to launch when this subscription is executed
  • <CacheFolder/>: The folder in which application data is cached
  • <FeedUri/>: The location of the feed generated as part of the previous topic
  • <ttl/>: How often to check the feed for updates
  • <RequiresAuthentication/>: Whether or not this feed requires authentication before it can be accessed
  • <AuthenticationUri/>: An item that can be requested to ensure that the provided credentials work

With this data, Subscription Center is able to automatically synchronize the application data so that it’s ready and waiting whenever photoSuru – or any application you create with the starter kit – needs it. Users can install subscriptions by double-clicking a .subscription file, or opening one from a web link.

The content of the feed at FeedUri is automatically cached by Subscription Center for use by the application, even when the user is not connected to a network. The files are cached in a SQL Server Compact Edition database which is unique to the application. Thus, this data is only accessible by the application associated with that subscription.

photoSuru gets its data through Subscription Center so that it can take advantage of the updating and caching Subscription Center does on its behalf.

When a user opens a subscription in Subscription Center, it reads the subscription manifest and launches the application specified in ApplicationPath, providing the path to the subscription manifest to the application via the /Subscription command line argument. photoSuru, upon being launched with the /Subscription command line argument, reads the subscription manifest for information about the subscription – including the application theme to use and the location of the feed to read – and then begins requesting data for the feed, starting with the content feed, from Subscription Center. Since Subscription Center is responsible for syncing and caching data from a feed, any files that photoSuru requests through it – whether they are feeds, images, text description files, or anything else – are automatically up-to-date and accessible offline.

If the application is not installed and the application path is a URI to a ClickOnce deployed application, the application install will be invoked when the user clicks on the subscription in Subscription Center. Note that even if the associated view application is not yet installed, Subscription Center will sync/download the content for any registered subscription; however, by using a ClickOnce URL to a non-installed application, the application will not be able to launch with multiple subscriptions while offline.

If the file requested by photoSuru is not cached (due to the file not being listed in the parsed feeds), then Subscription Center will indicate that the file cannot be found. However, if the file requested by photoSuru is not cached because Subscription Center is in the middle of a sync (e.g. the first sync) and hasn’t yet got to downloading that file, Subscription Center will skip that request to the head of the queue and process it as soon as possible; this allows the thumbnails in the gallery home to load before all of the rest of the content on the first sync, making the application usable even though only a small percentage of the total data has been loaded.

If photoSuru is not launched with the /Subscription parameter, then it uses the default theme and feed specified in ScePhotoViewer\Properties\Settings.settings, in keys DefaultApplicationThemeName and DataFeedUri, respectively.

Upon startup, photoSuru iteratively reads its feeds, requests the data items from Subscription Center, and builds its data model.

Subscription Center doesn’t care what type of content it is caching (with the exception of RSS feeds, which it understands and parses to determine which files to download and/or update); it simply caches information. Therefore, when photoSuru starts up, it starts by requesting the active subscription’s content feed. It parses this feed, finds the Gallery feeds it references, and then constructs PhotoGallery objects for these items. It then continues deeper in the feed structure, constructing PhotoAlbum objects from the Album Feeds, and Photo objects for each item referenced in the Album feeds. Since all of these file requests are brokered through Subscription Center, which searches its cache for these items, this process works identically whether the user is currently online or offline. All of this decoding of feeds occurs in the ScePhoto.Feed namespace, mostly in ScePhoto.Feed.PhotoFeedConverter.

At this stage, all of the metadata for the items described by the feeds has been loaded into memory; the image data itself is not loaded to keep the working set size for the application low. All of the information that was once in the feeds can now be accessed off of the DataManager’s (ScePhoto.Data.DataManager, access through ScePhoto.ServiceProvider.DataManager) PhotoGalleries collection; the ViewManager (ScePhoto.View.ViewManager, access through ScePhoto.ServiceProvider.ViewManager) has properties for the active photo gallery, album, and photo.

Whenever we need to display an image on the UI, we use a control that derives from ScePhoto.PhotoBaseControl to retrieve that image given the photo’s metadata. These controls – PhotoThumbnailControl, LargePhotoThumbnailControl, and PhotoViewerControl – request the image data from Subscription Center; Subscription Center then returns the cached data. When the controls are unloaded, this data is automatically garbage collected along with the control, keeping our working set low as only the photo metadata is kept in memory (we’ve seen test feeds with more than 1.7 GB of photos still perform well, since only a small amount of the image data is actually loaded at once).

Data Flow Recap

There’s four steps in the data flow of photoSuru: Start with photos, describe their structure and location with a series of feed files, publish a subscription with details for this feed and the application used to display it, and then run photoSuru to actually see your content.

Using the Feed Wizard

Use the feed wizard to quickly generate a subscription from a set of photo files you have – it automatically reads embedded tags to title, tag, and rotate files. Structure your files into Folders (Galleries) of Folders (Albums) of Photos for best results.

Open the Feed Wizard by clicking the very first arrow in the breadcrumb bar and selecting ‘Create Subscription’ from the menu that drops down. Or drag and drop a folder of photos on to photoSuru; photoSuru will automatically open the Feed Wizard and populate the path to the folder for you.

On the first page, select a folder of photos to generate the feed from. Just like the previous discussion on feed structure, selecting a structured folder will produce a better feed. The folder you select is the ‘Content’ feed level; the folders it contains become the feed’s galleries, and the folders they contain become the albums. The photos for your feed should be at the lowest level, inside the album folders. If some of these folder’s don’t exist, we’ll make them up – adding parent albums and galleries as necessary – but if you’re photos aren’t in the leaf folders of this structure, we won’t know where to put them and won’t include them in the feed.

On the second step, tell us a bit about your photos – what the subscription should be called, which photo should be used as a logo, what photoSuru theme we should use when displaying them, and whether you want us to downsample your photos. Downsampling is a good idea – most of the photos that come off of your camera are big – really big! – and needn’t be that big when displayed with photoSuru. Checking this option will downsample your images to 3 megapixels, which is good for viewing and a lot faster to download and sync. Also, to ensure things don’t get too out of hand, we’re limiting the size of generated feeds to 100 MB in this version so that images always download fairly quickly. Keeping this checked means more photos in each subscription! (if you run out of space in one subscription, try creating a second subscription with the images that didn’t fit in the first one).

The final step is where you provide the details of where your feed of photos will live, and changes based on the provider you set. Some providers may not require any settings, while others may require more information. Choose Manual Feed Upload if you plan to upload the files yourself to a server; just provide the final location where the feed will be stored so that we can write it to the subscription file. The manual generator will open up the folder to upload once it’s complete. Or choose Upload to local folder or remote share if you’re running the wizard on your file server, or can access the server through a UNC share path; provide the path to the folder where you want to copy the output files, and then the http:// location for that folder so that we can write out the correct links. Whatever you choose, clicking ‘Publish’ will generate a feed containing all the files you provided, with the correct metadata and feed structure, and then launch an email window with the link to your application (set this in ScePhotoViewer\Properties\Settings.settings as ApplicationDownloadLocation if you’re making your own application) so you can share your photos with your friends.

If your feed generator allows you to set the ‘Authenticate’ option, then selecting this box will mark the feed as an authenticated feed, and Subscription Center will prompt for credentials before it begins to sync. You’ll still have to set up the authentication itself on the server, however.

There’s a couple additional ways to provide information to the feed generator so that it builds a feed with the information you want. Here we’ll talk about how to set each field in the feed so that photoSuru displays the content you expect.

To set the name of the photo that photoSuru displays beneath the photo, use a photo tool like Windows Live Photo Gallery, Windows Picture Viewer, or some other tool that can write image metadata and set the Caption field. If the Caption field isn’t set, photoSuru will use the photo’s filename, less the file extension.

To add a long description of a photo, create a text file with the same name as the photo, in the same folder as the photo. For example, if you had ‘Microsoft.jpg’, then you’d create ‘Microsoft.txt’; the feed generator automatically copies this file over with the photo and adds a link to the feed so that this file is cached as well.

The short description of a photo – the part of the description that is overlayed over the bottom of the photo when descriptions are turned on – is derived from the long description file using the following heuristic: if the first paragraph is 160 characters or less, then the first paragraph becomes the short description. If the first paragraph is more than 160 characters long, then the first 160 characters plus the rest of the word in which the 160th character occurs are taken as the short description.

To set the photo’s tags, use a photo tool to tag the photo tool; the feed generator will read these tags out of the photo metadata and add these tags to the feed. Do not use spaces in your tags; tags with spaces will be treated as separate items.

Finally, the feed generator looks for EXIF orientation data, so if your camera saves which orientation a photo was taken in it will automatically rotate it to the correct orientation for display.

The feed wizard only generates feeds from JPEG or PNG files.

Customizing the Feed Wizard

By default, photoSuru only provides feed generators for manual upload and uploads to local directories/remote shares. But by extending our default generators, you can add a provider for your own service for no-configuration uploads!

To do this, create a subclass of ScePhotoFeed.FeedGenerator. Then all you have to do is override the implementation of UploadFiles() so that it uploads the provided directory of files to your own service or web location. You’ll want to delete the directory after upload – the provided directory is a temporary directory and not the original files. You’ll also need to create your own constructor that sets DisplayName and GenerationInstructions; DisplayName is the name of the generator as it appears in the menu of generators, and GenerationInstructions are the instructions presented to the user *after* generation has completed. If you need to display instructions before generation starts, add those instructions to your generator’s data template (more details below).

Also consider overriding some of the other functions:

  • UpdateGenerationProgress() should calculate the current generation progress including the uploading all of the files.
  • GetFeedAddress() can be overridden to return the correct path to the feed, with or without user input. For example, you might want to have this return a location on your service with the user’s username appended, so that the user can configure the generator by typing their username as opposed to a complicated-looking feed address. Or if you’re running this with already logged-in users, you can have this always return the correct value, without requiring any user configuration at all!

Once you’ve built your feed generator, create it in 'ScePhotoFeed\Wizards\FeedCreator.xaml.cs' CreateFeedGenerators() method; this tells the user interface to display the feed generator as one of the options to the user. The generators are displayed in the order they are listed in this method, so if you want yours to be the default make sure to list it first.

If you’re not planning on using the default template (which just prompts for a feed address), then add a default DataTemplate for your generator. This template will display before generation begins and allows you to prompt for additional details about the generation before generation starts and use those parameters during generation.

There are also a number of settings that you can configure for the feed generator, including thumbnail sizes, feed size caps, JPEG quality, and others. They’re all located in ScePhotoFeed\GenerationSettings.cs as constants at the top of the file.

Generating a Custom Feed

You can generate your own feeds based on content not on a file system – or organized differently – using the classes in the ScePhotoFeed namespace.

The SceSyndicationFeed object represents an SCE RSS feed, either the Content Feed or a Gallery or Album Feed. Add GalleryFeedItems – containing links to your gallery feeds – to a SceSyndicationFeed object to make a Content Feed; you can also add SubscriptionDetailsItems with details of a few photos; these items will show up in Subscription Center’s details view. Add AlbumFeedItems to a SceSyndicationFeed object to make a Gallery Feed, and add PhotoItems to a SceSyndicationFeed object to make an Album Feed. These classes allow you to build a correctly-formatted feed in an object-oriented fashion without worrying about how those objects get written to a well-formed RSS document (if you want to save one of these feeds to the file system, create an XmlTextWriter and use the feed’s WriteTo() method to write to it).

Remember that all of the files you reference in these feeds need to be accessible using HTTP GET requests over HTTP or HTTPS; Subscription Center doesn’t know how to talk to web services. You can, however, store feeds and files in an authenticated directory; you’ll just have to set the RequiresAuthentication and AuthenticationUri elements in the subscription file you generate.

One powerful way of constructing your feeds is to use a WCF service; these services can do many operations that allow you to generate feeds dynamically or from non-filesystem collections of photos like databases, online services, or other systems.

You generate your feeds the same way as you would if you were generating using local files, just using whatever metadata you have available to you to structure your feed (see our Case Study, the MS Give Auction Application, for an example of how we did this). Remember that everything needs to be HTTP GET accessible, so you might save the images out of your system to a temporary file location, or write a service that is able to proxy these items out. For the methods that generate the feeds, you can return the SceSyndictionFeeds directly; WCF will write their output as if it was a static RSS file.

For example, you may have a service like the following:

[OperationContract]
[WebGet(UriTemplate = "Feed.xml")]
Rss20FeedFormatter MasterFeed();

[OperationContract]
[WebGet(UriTemplate = "Feed/{gallery}.xml")]
Rss20FeedFormatter GalleryFeed(string gallery);

[OperationContract]
[WebGet(UriTemplate = "Feed/{gallery}/{album}.xml")]
Rss20FeedFormatter AlbumFeed(string gallery, string album);

If the service was running on localhost:8080/photoSuru, then you could use links like the following to access the feeds:

  • Content Feed: http://localhost:8080/photoSuru/Feed.xml
  • Gallery Feed for gallery ‘MyGallery’: http://localhost:8080/photoSuru/Feed/MyGallery.xml
  • Album Feed for album ‘MyAlbum’: http://localhost:8080/photoSuru/Feed/MyGallery/MyAlbum.xml

Subscription Center reads the service-generated feeds the same way as it reads static feed files, even though you’re generating these feeds dynamically.

It is important to consider how timestamps are written into your feed to ensure that Subscription Center works as intended. When it checks for updates, Subscription Center will always download your feed’s content feed and check its timestamp against the timestamp it has on file for that feed. If the feed is newer, it will check the gallery feeds for updates, and if any of those have changed, it will check the album feeds for a newer timestamp than it has cached, and if any of those have changed, it will check the photos they reference for a newer timestamp than it has cached for each photo. If, during any stage of this process, it encounters a timestamp equal to one that it has cached, it will not re-download that file or *any* of its children. Therefore, if you update a photo and its timestamp without updating the timestamp on its parent album, gallery, and content feed, Subscription Center will not update the file on computers already subscribed to the feed. Conversely, if all timestamps are set to DateTime.Now, all of the content in the feed will be re-downloaded, whether or not it has actually changed or not.

For simplicity, the feed generation classes that ship with photoSuru always set the timestamp on feeds to DateTime.Now, and on photo items themselves to the last time the item has changed (for photos on the file system, this is the ‘Date Modified’ file timestamp). This results in Subscription Center downloading the entire collection of feeds – not photos – every time the feed generator is run, which incurs a small overhead every time the generator is run, but which allows you to construct feeds with simpler logic that are more tolerant in their acceptance of timestamps. For generators that are run often – especially those running on a service – you should be sure to ‘bubble up’ the latest file timestamp from the photos in your feed – including additions and deletes – to the parent album feeds, from the album feeds to the gallery feeds, and back to the root content feed so that the additional download overhead is eliminated.

Each item in one of the feeds has two timestamps:

  • The csx:lastBuildDate element is what Subscription Center uses to detect changes in what it has downloaded, as described above.
  • The pubDate element is used when csx:lastBuildDate is not available; for times when csx:lastBuildDate has been written to the feed, it can be useful to set this to the current time (or the time of the last feed generation if using static or cached feeds) when debugging so that you can see each feed generator run occur without breaking the Subscription Center feed updating logic.

Using a Feed

Whether or not you’re using the feed wizard, generated subscriptions aren’t automatically installed. Double click the .subscription file (or paste the subscription link into your browser) to run the subscription an install it into Subscription Center.

When you run a subscription from Subscription Center, it launches the application at the location specified by the application’s manifest in the ApplicationPath element. This path is relative to the users’ AppData\Local ([Drive]:\Users\[UserName]\AppData\Local) folder if an absolute path to the application is not provided. If you’ve customized photoSuru into your own application, make sure to change the GeneratedFeedApplicationName setting in ScePhotoViewer\Properties\Settings.settings; otherwise, the original photoSuru will launch instead of your application when the subscription is run. Since this setting changes what is written into the subscription file, you’ll have to do this *before* you generate any subscriptions (or you’ll have to generate them again). You’ll also want to make sure that the ClickOnce settings matches this name.

To set the feed that photoSuru displays when no subscription is passed to it by Subscription Center – which happens when it is launched at the end of the setup process, as well as when the user double clicks the photoSuru icon on their desktop – set the DataFeedUri setting in ScePhotoViewer\Properties\Settings.settings. Note that Subscription Center will synchronize this feed *only* when the application is running unless a subscription that contains the same feed address is also installed into Subscription Center.

To delete photos from Subscription Center, right click on the subscription and click ‘Delete’; alternatively, you can press the delete key on your keyboard with the subscription you wish to delete selected.

Note

This document is also available from within photoSuru; simply open the ‘Application Content’ album in the ‘How To photoSuru’ subscription that installs with photoSuru.

Featured Item