Working with Windows 8 user pictures (.accountpicture-ms)

BACKGROUND

First of all, I love Windows 8. I have it on all of my computers and I find that is the best OS for productivity and awesomeness.

Microsoft has changed a lot of things on Windows 8 comparing to Windows 7, and one of these things is the way the Windows stores the user pictures.

When i started developing MetroSidebar, i developed a User Account tile which displays the user picture, user name and PC name.

I thought it would be easy because i did it many times on Windows 7 but i found that it’s completely different, and here what i found:

In Windows 8, the user pictures are not saved as image files like JPEGs or BMPs or or or, they are saved as .accountpicture-ms (weired isn’t it?!).

The profile pictures are stored in this directory Environment.SpecialFolder.ApplicationData, “\Microsoft\Windows\AccountPictures” with the extension .accountpicture-ms.

To get the file name you need to move the mouse over the image file

Then you can see it in the tooltip (in my case it’s “673c064405e4b2fd”).

The problem is that these are not images, they are Account Picture files with extension “.accountpicture-ms”, in fact, I don’t think there is any program that can open this type of file (except Windows Explorer).

COMPOSITION:

The “.accountpicture-ms” files contain a file type definition and two *.jpg images.

The type definition is used to define the file type, so even if you change the extension to *.jpg, you won’t be able to read the file.

The images are stored in two different extensions one in 96×96 pixels and the other in 448×448 pixels.

READING THE IMAGES:

We’ll start by reading the 96×96 pixels image:

The first thing we need to do is to load the file using a FileStream:


FileStream fs = new FileStream(path, FileMode.Open);
long position = Seek(fs, "JFIF",0);

Then converting the FileStream to BitmapImage:


public BitmapImage GetImage96(string path)
{
FileStream fs = new FileStream(path, FileMode.Open);
long position=Seek(fs, "JFIF", 0);
byte[] b = new byte[Convert.ToInt32(fs.Length)];
fs.Seek(position-6, SeekOrigin.Begin);
fs.Read(b, 0, b.Length);
fs.Close();
fs.Dispose();
return GetBitmapImage(b);
}

Now to read the 448×448 pixels image:

public BitmapImage GetImage448(string path)
{
FileStream fs = new FileStream(path, FileMode.Open);
long position = Seek(fs, "JFIF", 100);
byte[] b = new byte[Convert.ToInt32(fs.Length)];
fs.Seek(position-6, SeekOrigin.Begin);
fs.Read(b,0,b.Length);
fs.Close();
fs.Dispose();
return GetBitmapImage(b);
}

To Convert byte array to BitmapImage:

public static BitmapImage GetBitmapImage(byte[] imageBytes)
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = new MemoryStream(imageBytes);
bitmapImage.EndInit();
return bitmapImage;

}

As you notice i used the Seek method, this method allows me to start reading the bytes from a chosen byte.

The seek method:

public static long Seek(System.IO.FileStream fs, string searchString, int startIndex)
{
char[] search = searchString.ToCharArray();
long result = -1 ,position = 0 ,stored = startIndex,
begin = fs.Position;
int c;
while((c = fs.ReadByte()) != -1)
{
if((char)c == search[position])
{
if(stored == -1 && position > 0 && (char)c == search[0])
{
stored = fs.Position;
}
if(position+1 == search.Length)
{
result = fs.Position - search.Length;
fs.Position = result;
break;
}
position++;
}
else if(stored > -1)
{
fs.Position = stored+1;
position = 1;
stored = -1;
}
else
{
position = 0;
}
}

if(result == -1)
{
fs.Position = begin;
}
return result;

}

2 thoughts on “Working with Windows 8 user pictures (.accountpicture-ms)

  1. ive got an error on “BitmapImage” references is this a method ?
    can you please email me a complete working C# winforms applications’ source code. I’d be greatful for it!

  2. I’m having a problem with the source code in my project and it’d be of great help if you could send me a sample project which only gets the user account picture onto a picture box control.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

code