# Friday, December 28, 2012

Missing Simulator and Local Machine Debugging Modes in Visual Studio 2012 for Windows Store Apps

My buddy got bit by this one on stage during a demo. When you're not under pressure, the answer may be more obvious then when all the eyes in the room are on you and your dropdown box is missing a few items.

If you try to launch a Windows Store app using Visual Studio 2012 and you don't see the Simulator or Local Machine options in the Debugging Mode dropdown box, then you've probably set the Build Target to ARM.

Change the Build Target using the Configuration Manager window, and your back in business.

Debugging Modes

Configuration Manager

#    Comments [0] |
# Wednesday, December 19, 2012

First and Last Post of 2012

This has been one of the more memorable years with moving to a new house, my boy turning four, working on awesome projects, running consistently and getting into the best shape I've been since my twenties.

Looking forward to 2013, even though I have this strange propensity to select even numbers on thermostat and volume controls.

#    Comments [1] |
# Wednesday, August 24, 2011
# Wednesday, June 01, 2011

How to unlink images from your Word 2010 document

Well that was way too hard.

I inadvertently sent a Word document out that included some images. The images were linked instead of being embedded in my document. I still don't know how I could have known that unless I previewed the document on another PC. The images were linked to a local folder on my PC. When another person opened my Word document, the images were missing.

After way too much searching, I found this link that shows how to unlink images in your Word document so they're embedded.

I needed to configure Word to display the Prepare tab, then select the "Edit Links to Files" menu item under the "Prepare" group. Note, this menu item only appears when you actually have linked files in your document. Grrrrr... When I select this menu item a modal dialog opens and I can select each linked image (one-by-one) and check the box labeled "Save picture in document".

Now anyone can open my Word document and see the embedded images. There's got to be a better way of doing this, but I haven't found it yet.

#    Comments [0] |
# Thursday, March 03, 2011

Getting to know Easel.js

I've been having some fun with easel.js, an abstraction layer that makes programming interactive HTML5 code a little less painful. It's mostly about the canvas tag, but there are some other general purpose interactive nuggets too.

The library includes 20+ samples to help you learn the code, including a fancy moving bar graph and animated rats!

I modified the animated rat sample to show the loveable animal walking at different rates. Even with the IE9 RC, you need to keep a sharp eye on performance.

In my modified sample, I extracted a sprite and updated an img tag on every "tick" exposed by easel.js library. The screenshot below shows my processor when the tick frequency was at 1ms, 10ms and 50ms respectively.

Easel.js performance on IE9 RC

This was just HTML, as the code doesn't use the canvas tag to implement the animation. I wonder how that would affect performance.

Here's my modified code from the easel.js samples; you'll need to reference the libraries if you want to run it yourself.

Modified extractFrame.html (2.18 KB) easel.js sample

#    Comments [0] |
# Saturday, February 26, 2011

Boise Code Camp 2011

Shopping List App I had a great time presenting Windows Azure at the Boise Code Camp today. This is a great venue and I'm enjoying the awesome talks.

Adam Cogan kicked off the event with his keynote and I'm winding down with Glenn Block in his REST talk.

You can download my Azure presentation. Inside the zip file, you'll find my slide deck, helpful nuggets and the sample Shopping App solution I used to demonstrate some features of Windows Azure.

I've also created a short list of helpful Azure links that relate to some of my Azure speaking points. I hope you enjoyed the event as much as I did!

#    Comments [0] |
# Friday, November 05, 2010

Playing Audio with Silverlight on Mac OSX

So, who out there already knew what a coworker and I just learned via trial and (mostly) error?

Jim and I were working on a simple Silverlight audio player with a couple of tracks, nothing elaborate whatsoever. It runs great on Windows. Yet, it failed to play audio on Mac OSX, regardless of browser.

After a bit of voodoo, standing on one foot and other meaningless postulates, Jim says, “Hey, can you move the player back onto the screen so we can see the trace statements?” I was using CSS to position the player off the screen, as it has no user interface. Jim was showing trace events in a simple textblock.

As soon one pixel of the Silverlight control existed inside the visible browser viewport, the audio would play on our Macbook Pro. Move it off the screen, then no audio for you.

But wait there’s more! Setting CSS visibility to hidden works in Mac/Safari, but still fails in Mac/Firefox. To play in all browsers, the Silverlight player must have at least one visible pixel on the screen. I didn’t try layering it behind another element because a single dot on our page was invisible on the edge.

Uhg.

#    Comments [0] |
# Friday, August 20, 2010

Configuring a local SQL Server Instance with Azure

I was using a clean machine for some Azure development and it just happened to have the developer edition of SQL Server, as the default instance, installed instead of SQL Server Express Edition. When I pressed F5 to launch the local developer app fabric, I received an error message about the local developer storage. By default, the local developer storage is looking for .\SQLExpress on your machine.

Here’s the error message that popped up in Visual Studio 2010:

Failed to initialize Development Storage service. See output window for more information.

I looked in the output window and found this message:

Windows Azure Tools: Failed to initialize Development Storage service. Unable to start Development Storage. Failed to start Development Storage: the SQL Server instance ‘.\SQLExpress’ could not be found.   Please configure the SQL Server instance for Development Storage using the ‘DSInit’ utility in the Windows Azure SDK.

I needed to configure the default instance of SQL Server for Azure local development. So I searched online for “Azure DSInit” and the first hit shows how to invoke the command.

http://msdn.microsoft.com/en-us/library/dd179457.aspx

To configure development storage against the default SQL Server instance:

DSInit /sqlInstance:.

The program DSInit.exe is found in the Azure SDK:

C:\Program Files\Windows Azure SDK\v1.0\bin\devstore\

Once I ran that program to initialize the local development app storage, I was off and running with my cloud development tasks.

#    Comments [0] |
# Thursday, August 19, 2010

Dinking around with the Facebook JavaScript SDK

With some spare time on my hands, I took at look at the improved JavaScript SDK from Facebook.

In the past, I really disliked Facebook coding because the developer experience was really hard. The documentation was wrong or obsolete, the sample code libraries rarely worked and it was really frustrating.

Now with the push towards the JavaScript SDK, things are smooth sailing! Here’s the reference: http://developers.facebook.com/docs/reference/javascript/

It’s super easy to sign in to Facebook from my external site and remove the need to have my own authentication system. I’m always a fan of having one less username and password to remember. The following sample page can be used to connect to your facebook application and do a couple of simple tasks like retrieving your name. This Facebook code comes right out of the JavaScript SDK reference.

The 5 steps to set up this code are embedded in comments of this HTML file:

   1: <!DOCTYPE html>
   2: <html lang="en">
   3: <head>
   4:     <title>Sample Facebook JavaScript SDK</title>
   5:  
   6:     <!--
   7:         How to get started:
   8:  
   9:             1. Register an app on http://www.facebook.com/developers/
  10:             2. Helpful table of facebook app settings can be found here: http://msdn.microsoft.com/en-us/windows/ee395718.aspx
  11:             3. Create a Web Forms or MVC project in Visual Studio
  12:             4. Inside Visual Studio, set the specific PORT NUMBER to match the Facebook app registration
  13:             5. Copy your app id from Facebook registration page to the JavaScript below
  14:     -->
  15:  
  16:     <style>
  17:         input {
  18:             width:130px;
  19:         }
  20:         table {
  21:             width:100%;
  22:         }
  23:         .left {
  24:             width:200px;
  25:             vertical-align:top;
  26:             text-align:left;
  27:         }
  28:         .right {
  29:             vertical-align:top;
  30:             text-align:left;
  31:         }
  32:     </style>
  33: </head>
  34: <body>
  35:  
  36:     <table>
  37:         <tr>
  38:             <td class="left">
  39:                 <ol>
  40:                     <li>
  41:                         <input id="getLoginStatusButton" type=button value="Get Login Status" />
  42:                     </li>
  43:                     <li>
  44:                         <input id="loginButton" type=button value="Login" />
  45:                     </li>
  46:                     <li>
  47:                         <input id="getName" type="button" value="Get Name" />
  48:                     </li>
  49:                     <li>
  50:                         <input id="logoutButton" type="button" value="Logout" />
  51:                     </li>
  52:                 </ol>
  53:             </td>
  54:             <td class="right">
  55:                 <h2>Messages</h2>
  56:                 <ol id="messages"></ol>
  57:             </td>
  58:         </tr>
  59:     </table>
  60:     
  61:     <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js"></script>
  62:     <script type="text/javascript">
  63:  
  64:         window.fbAsyncInit = function () {
  65:             FB.init({
  66:                 appId: '[YOUR APP ID GOES HERE]',
  67:                 status: true, 
  68:                 cookie: true,
  69:                 xfbml: true
  70:             });
  71:         };
  72:  
  73:         $(function () {
  74:  
  75:             $('#getLoginStatusButton').click(function () {
  76:                 console.log('inside button click event');
  77:                 FB.getLoginStatus(function (response) {
  78:                     if (response.session) {
  79:                         // logged in and connected user, someone you know
  80:                         $('#messages').append('<li>logged in; access token is ' + response.session.access_token + '</li>');
  81:                     } else {
  82:                         // no user session available, someone you dont know
  83:                         $('#messages').append('<li>not logged in</li>');
  84:                     }
  85:                 });
  86:             });
  87:  
  88:             $('#loginButton').click(function () {
  89:  
  90:                 FB.login(function (response) {
  91:                     if (response.session) {
  92:                         // user successfully logged in
  93:                         $('#messages').append('<li>successful log in; access token is ' + response.session.access_token + '</li>');
  94:                     } else {
  95:                         // user cancelled login
  96:                         $('#messages').append('<li>cancelled logged in</li>');
  97:                     }
  98:                 });
  99:  
 100:             });
 101:  
 102:             $('#getName').click(function () {
 103:  
 104:                 FB.api('/me', function (response) {
 105:                     $('#messages').append('<li>' + response.name + '</li>');
 106:                 });
 107:  
 108:             });
 109:  
 110:             $('#logoutButton').click(function () {
 111:  
 112:                 FB.logout(function (response) {
 113:                     $('#messages').append('<li>logged out</li>');
 114:                 });
 115:  
 116:             });
 117:  
 118:         });
 119:  
 120:     </script>
 121:     
 122:     <div id="fb-root">
 123:         <script src="http://connect.facebook.net/en_US/all.js" type="text/javascript"></script>
 124:     </div>
 125:  
 126: </body>
 127: </html>
#    Comments [0] |
# Monday, August 16, 2010

How to Edit Meta Data Inside JPG Files with C#

I do (change your EXIF data)We just got back from a great weekend at the beach; my sister-in-law got married on the sands near Haystack Rock in Cannon Beach, OR. Really a great trip from start to finish.

My wife accepted the photographer duties and snapped nearly 2K photos with our Nikon D40 and a Nikon D60 that we borrowed from a friend. She had a zoom lens on one and a short lens on the other to avoid the need to change lenses in mid-moment. That part worked great.

The part that we overlooked was the current date/time on each camera; they were not synchronized. This will make sorting photos by time more difficult. No problem, I say, on the drive back home. I’m a developer and JPG files have meta info that I can manipulate, right?

It turns out that its not all that easy. Its actually a remarkable pain in the ass, hence this blog post (that’s the remark-able part).

I started with an online search and found Hanselman’s post about combining PowerShell with Omar Shahine’s library, ImageLibrary.dll that is evidently no longer accessible. Big phat 404 while trying to get that assembly.

Next, I did some searches specific to StackOverflow.com and saw some posts about how difficult reading/writing this meta data can be. At this point, I was beginning to wonder if my wife was going to hear a broken promise or not. It wasn’t looking good.

I found out that JPG files store meta data using EXIF, or Exchangeable Image File Format, a standard used by the digital still camera industry. It looked like C# 4.0 could crack this open, but I might have to do get my hands dirty with some bit shuffling. No worries, I was up for it. It didn’t look like there was a library out there that was going to fall into my lap, so I cracked open Visual Studio 2010 and saw what kind of trouble I could get into with Intellisense and a gin and tonic.

Let’s Take It Out for a Loop

I created a new project, loaded a Bitmap class with a sample JPG and iterated over the properties:

   1: using System;
   2: using System.Drawing;
   3:  
   4: namespace ReadExifInJPG
   5: {
   6:     class Program
   7:     {
   8:         static void Main()
   9:         {
  10:             var bitmap = new Bitmap("c:\\temp\\somephoto.jpg");
  11:  
  12:             foreach (var item in bitmap.PropertyItems)
  13:             {
  14:                 Console.WriteLine("Id: {0}, Type: {1}, Value: {2}", 
  15:                     item.Id, item.Type, item.Value);
  16:             }
  17:         }
  18:     }
  19: }

I had lots of properties in my sample photo:

output of simple iteration

I was thinking that this was going to be smooth sailing until I saw the values listed as byte arrays. Ugh. Then I read a EXIF specification that said the values can be stored in multiple formats and there are a ton of properties. I had over fifty on a single JPG image. I needed to find the property that told me if the given photo was taken by a Nikon D60 or a D40, and then change the date on the D60 images. Here’s the EXIF specifications: http://www.exif.org/specifications.html, and what a great document to read! Ugh.

I Just Want My Property

I found a list of property tags in numerical order on MSDN, note the id values are listed in hex, so 0x0132 (hex) equals 306 (decimal): http://msdn.microsoft.com/en-us/library/ms534418(VS.85).aspx

When you go about reading or changing a given property, there are three parts to consider:

  1. the id number that identifies the given property
  2. the type number which describes the data format
  3. the actual data, encoded in the least accessible format you could want

Here’s a list of numeric types that identify the corresponding data format:

  1. A Byte
  2. An array of Byte objects encoded as ASCII
  3. A 16-bit integer
  4. A 32-bit integer
  5. An array of two Byte objects that represent a rational number
  6. Not used
  7. Undefined
  8. Not used
  9. SLong
  10. SRational

Fortunately, everything I was interested in was of type 2, a byte array. This is a great MSDN article that gave me a bunch of tips on how to manipulate the EXIF data: http://msdn.microsoft.com/en-us/library/xddt0dz7.aspx

The property id of 306 holds the date of the photo, its a type 2 property, so the value is stored in a byte array. Here’s how to read the string value:

   1: var property = bitmap.GetPropertyItem(306);
   2: System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
   3: string value = encoding.GetString(property.Value);


Caution, Byte Counting Ahead

Note, the date properties that I’m interested in updating have values stored as byte arrays. More specifically, they’re exactly 20 bytes long. At first I wasn’t respecting that boundary and I just let .Net do it’s thing to convert my formatted date string into a byte array. When I tried to read the value back, it was empty because I overflowed the value.

After some noodling, I changed my code to write out exactly 20 bytes of data, starting at precisely 23 bytes into my new byte array, as follows.

   1: private void ChangeTimeStamp(Bitmap bitmap, int minutesToAdd)
   2: {
   3:     DateTime originalDateTime = GetOriginalDateTime(bitmap);
   4:  
   5:     var newDateTime = originalDateTime.AddMinutes(minutesToAdd);
   6:  
   7:     BinaryFormatter bf = new BinaryFormatter();
   8:     MemoryStream ms = new MemoryStream();
   9:     string formattedNewDateTime = newDateTime.ToString("yyyy:MM:dd HH:mm:ss");
  10:     bf.Serialize(ms, formattedNewDateTime);
  11:     ms.Seek(0, 0);
  12:  
  13:     var tempArray = ms.ToArray();
  14:  
  15:     byte[] byteArray = new byte[20];
  16:  
  17:     var x = 0;
  18:     for (int i = 23; i < (23 + 19); i++)
  19:     {
  20:         byteArray[x] = tempArray[i];
  21:         x++;
  22:     }
  23:  
  24:     SetNewDateTime(bitmap, byteArray, 306);
  25:     SetNewDateTime(bitmap, byteArray, 36867);
  26:     SetNewDateTime(bitmap, byteArray, 36868);
  27: }
 

Note, the previous code shows I’m writing the same date to three different property settings (306, 36867, and 36868). They all had the same date value, so I figured the best thing to do was keep them all in sync.

It Works on My Machine

So, I was finally done with the code and I tested it with a bunch of files on my machine. Worked great. I installed VS 2010 C# Express on my netbook so I could create a console application and run it on my wife’s laptop. I had been abusing a ASP.Net Web Forms application with Visual Web Developer Express on my netbook. I made a quick console app, copied it to my wife’s laptop and ka-pow! It no worky. Puzzled, I tried to think what was wrong for about 30 minutes. After a couple of assertions inserted into my code, I realized she had some non-JPG files in the folder and my program wasn’t filtering for only JPG files. Doh! I did manage to get in a quick “hey, it works on my machine” comment to my wife, but she didn’t think it was as funny as I did.

Nothing But The Code, The Whole Code, So Help Me .Net Runtime?

Here’s the final class I built, in “good enough” format. The entire coding time, not including the installation of VS 2010 Express on my netbook, or .Net 4 on my wife’s laptop was about 90 minutes. The console program just takes this class, passes in the source and destination directories, along with the number of minutes to adjust the timestamp on the photo.

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.IO;
   6: using System.Drawing;
   7: using System.Runtime.Serialization.Formatters.Binary;
   8:  
   9: namespace ImageMetaTool
  10: {
  11:     public class TimeEditorService
  12:     {
  13:         public void AdjustDateTime(string soureDir, string destDir, int minutesToAdd)
  14:         {
  15:             if (!Directory.Exists(soureDir))
  16:             {
  17:                 Console.WriteLine("Source directory does not exist.");
  18:                 return;
  19:             }
  20:  
  21:             if (!Directory.Exists(destDir))
  22:             {
  23:                 Console.WriteLine("Destination directory does not exist.");
  24:                 return;
  25:             }
  26:  
  27:             int x = 0;
  28:             var list = Directory.GetFiles(soureDir, "*.jpg");
  29:             foreach (var filename in list)
  30:             {
  31:                 Console.WriteLine("Processing image {0} of {1}; {2}", x, list.Length, filename);
  32:  
  33:                 using (var fs = File.OpenRead(filename))
  34:                 {
  35:                     var bitmap = new Bitmap(fs);
  36:                     ProcessFile(bitmap, minutesToAdd);
  37:                     bitmap.Save(Path.Combine(destDir, Path.GetFileName(filename)));
  38:                     x++;
  39:                 }
  40:             }
  41:  
  42:             Console.WriteLine("Processing completed.");
  43:         }
  44:  
  45:         private void ProcessFile(Bitmap bitmap, int minutesToAdd)
  46:         {
  47:             if (!IsD60(bitmap))
  48:                 return;
  49:  
  50:             ChangeTimeStamp(bitmap, minutesToAdd);
  51:         }
  52:  
  53:         private void ChangeTimeStamp(Bitmap bitmap, int minutesToAdd)
  54:         {
  55:             DateTime originalDateTime = GetOriginalDateTime(bitmap);
  56:  
  57:             var newDateTime = originalDateTime.AddMinutes(minutesToAdd);
  58:  
  59:             BinaryFormatter bf = new BinaryFormatter();
  60:             MemoryStream ms = new MemoryStream();
  61:             string formattedNewDateTime = newDateTime.ToString("yyyy:MM:dd HH:mm:ss");
  62:             bf.Serialize(ms, formattedNewDateTime);
  63:             ms.Seek(0, 0);
  64:  
  65:             var tempArray = ms.ToArray();
  66:  
  67:             byte[] byteArray = new byte[20];
  68:  
  69:             var x = 0;
  70:             for (int i = 23; i < (23 + 19); i++)
  71:             {
  72:                 byteArray[x] = tempArray[i];
  73:                 x++;
  74:             }
  75:  
  76:             SetNewDateTime(bitmap, byteArray, 306);
  77:             SetNewDateTime(bitmap, byteArray, 36867);
  78:             SetNewDateTime(bitmap, byteArray, 36868);
  79:         }
  80:  
  81:         private void SetNewDateTime(Bitmap bitmap, byte[] newDateTime, int propertyNumber)
  82:         {
  83:             var property = bitmap.GetPropertyItem(propertyNumber);
  84:             property.Value = newDateTime;
  85:  
  86:             bitmap.SetPropertyItem(property);
  87:         }
  88:  
  89:         private DateTime GetOriginalDateTime(Bitmap bitmap)
  90:         {
  91:             var property = bitmap.GetPropertyItem(306);
  92:  
  93:             System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
  94:             string value = encoding.GetString(property.Value);
  95:  
  96:             string value2 = value.Split(' ')[0].Replace(":", "/") + " " + value.Split(' ')[1];
  97:  
  98:             return DateTime.Parse(value2); //2010:08:14 14:23:14
  99:         }
 100:  
 101:         private bool IsD60(Bitmap bitmap)
 102:         {
 103:             var modelProperty = bitmap.GetPropertyItem(272);
 104:  
 105:             System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
 106:             string modelName = encoding.GetString(modelProperty.Value);
 107:  
 108:             if (modelName.Contains("D60")) // NIKON D60
 109:                 return true;
 110:  
 111:             return false;
 112:         }
 113:     }
 114: }

 

I hope you have a good time futzing with your EXIF data!

#    Comments [0] |