Thursday, November 22, 2012

How to add test images on the Windows Phone emulator

When developing an app, and especially a photo app, it is common to have the need
to access photos from the Media Library of the phone in order to test and debug the code if necessary. The Windows Phone emulator comes with some sample photos (7 photos
on WP7 and 8 photos on WP8):
While that helps for basic testing like opening a photo, I like being able to test
with pictures I specifically chose. That way, I can test my app with different kind
of pictures, with different resolutions, etc. In this article, I will show you how
to add your test images to the emulator.

What I wanted was:

  • being able to add specific images in the media library
  • don't affect the XAP size when compiling in Release
  • don't affect performance when running in Release
  • only add images when running in the emulator (my device already has a lot of images
    to test with)

Steps:

1 - Create the 'TestImages'  directory in the project and add your test images

2 - Set the 'Build action' to 'Content' on the files in the Visual Studio properties 

3 - Edit the .csproj (right click on the project, 'Unload Project' then right click,
'edit .csproj') 

4 - Add the configuration condition on the lines that include the files in the project, like this:

<Content Include="TestImages\img1.jpg" Condition="'$(Configuration)' == 'Debug'" />

5 - Add the following code in the App constructor:

#if DEBUG
            if (Microsoft.Devices.Environment.DeviceType == DeviceType.Emulator)
            {
                EmulatorHelper.AddDebugImages();
            }
#endif

6 - Add the EmulatorHelper class:

using System;
using System.Collections.Generic;
using System.IO.IsolatedStorage;
using Microsoft.Xna.Framework.Media;
 
namespace MyPhotoApp
{
    public static class EmulatorHelper
    {
        const string flagName = "__emulatorTestImagesAdded";
 
        public static void AddDebugImages()
        {
            bool alreadyAdded = CheckAlreadyAdded();
            if (!alreadyAdded)
            {
                AddImages();
                SetAddedFlag();
            }
        }
 
        private static bool CheckAlreadyAdded()
        {
            IsolatedStorageSettings userSettings = IsolatedStorageSettings.ApplicationSettings;
 
            try
            {
                bool alreadyAdded = (bool)userSettings[flagName];
                return alreadyAdded;
            }
            catch (KeyNotFoundException)
            {
                return false;
            }
            catch (ArgumentException)
            {
                return false;
            }
        }
 
        private static void SetAddedFlag()
        {
            IsolatedStorageSettings userSettings = IsolatedStorageSettings.ApplicationSettings;
            userSettings.Add(flagName, true);
            userSettings.Save();
        }
 
        private static void AddImages()
        {
            string[] fileNames = { "img1""img2""img3""img4""img5" };
            foreach (var fileName in fileNames)
            {
                MediaLibrary myMediaLibrary = new MediaLibrary();
                Uri myUri = new Uri(String.Format(@"TestImages/{0}.jpg", fileName), UriKind.Relative);
 
                System.IO.Stream photoStream = App.GetResourceStream(myUri).Stream;
                byte[] buffer = new byte[photoStream.Length];
                photoStream.Read(buffer, 0, Convert.ToInt32(photoStream.Length));
                myMediaLibrary.SavePicture(String.Format("{0}.jpg", fileName), buffer);
                photoStream.Close();
            }
        }
    }
}
What you have now is a project that automatically adds test images to the Windows Phone Photo
Library, at the condition that
  • the build Configuration is 'Debug'
  • the app is running in the emulator
  • the images have not already been added
The advantage is that is does not impact the Release XAP in any way (performance
or size).

11 comments:

  1. Great solution, thank for sharing!

    ReplyDelete
  2. I'm getting the following exception in this line:

    myMediaLibrary.SavePicture(String.Format("{0}.jpg", fileName), buffer);



    {System.UnauthorizedAccessException: Attempted to perform an unauthorized operation.
    at Microsoft.Xna.Framework.Media.MediaLibrary.SavePicture(String name, Stream source)
    at Microsoft.Xna.Framework.Media.MediaLibrary.SavePicture(String name, Byte[] imageBuffer)
    at TeacherClassesLayout.EmulatorHelper.AddImages()
    at TeacherClassesLayout.EmulatorHelper.AddDebugImages()
    at TeacherClassesLayout.App..ctor()}

    ReplyDelete
    Replies
    1. Thats because I've forgotten to add the MediaLib capability.

      Delete
    2. This comment has been removed by the author.

      Delete
  3. what is " DeviceType.Emulator"
    in code

    5 - Add the following code in the App constructor:

    #if DEBUG
    if (Microsoft.Devices.Environment.DeviceType == DeviceType.Emulator)
    {
    EmulatorHelper.AddDebugImages();
    }
    #endif

    ReplyDelete
    Replies
    1. Try with "Microsoft.Devices.DeviceType.Emulator".
      It is an enum value that indicates the code is running inside the emulator.

      Delete
    2. This comment has been removed by the author.

      Delete
    3. It looks like the app can't find the images. Did you add sample images in the specified directory and set the 'Build action' to 'Content' in the Visual Studio properties?

      Delete