Freigeben über


Accessing photos in Facebook


Hello everyone and welcome to a new episode of the Facebook integration for Windows Store App series. Christophe Nasarre, a French Premier Field Engineer is explaining how to list the photos of Facebook albums and how the paging mechanism works.

The source code is available here .

For your convenience, here’s the video timeline:

[0:32] How to get Facebook .NET SDK in your Visual Studio project

[2:41] C# mapping of a Photo

[3:32] The PhotoBatch class and paging mechanism in Facebook

[4:30] Parsing of Json for Photo retrieval

[8:36] Parsing of Json for PhotoBatch and paging details

[10:01] App UI and binding to albums

[12:02] Updating album photos asynchronously via BitmapImage

[12:54] Back and Next button handlers

 

Preview of the expected result

Here is what I want to achieve:

image

When the user clicks the Albums button, its existing Facebook photo albums are listed with their name and cover picture. When an album is selected, its photos are listed. Facebook is returning only a subset of photos and the user can navigate between chunks with the Previous/Next buttons.

Exploring the photo Facebook API

As explained in the previous episode, Facebook albums are retrieved via a GET /me/albums request. The Json response contains the album id that is used to get its photos. As usual, go to the Facebook documentation and start a session in the Graph Explorer to figure out how to get the information you need.

Start from the Album endpoint and submit the /me/albums request to get an album id. In Graph Explorer, change the query to add the /photos suffix to the album id:

image

And submit to get the list of photos in this album via a Json list with the usual “data” root

image

Click a photo id to see its fields definition:

{

    "id": "1445644205718736",

    "created_time": "2014-07-27T09:55:42+0000",

    "from": {

        "id": "1448132418803248",

        "name": "Mspfe Gbs"

    },

    "height": 438,

    "icon": "https://fbstatic-a.akamaihd.net/rsrc.php/...gif",

    "images": [

        {

            "height": 585,

            "source": "https://scontent-b.xx.fbcdn.net/hphotos-xpa1/...jpg",

            "width": 960

        },

        {

            "height": 480,

            "source": "https://scontent-b.xx.fbcdn.net/hphotos-xpa1/...jpg",

            "width": 787

        },

        {

            "height": 320,

            "source": "https://scontent-b.xx.fbcdn.net/hphotos-xpa1/...jpg",

            "width": 525

        },

        {

            "height": 540,

            "source": "https://scontent-b.xx.fbcdn.net/hphotos-xpa1/...jpg",

            "width": 886

        },

        {

            "height": 130,

            "source": "https://scontent-b.xx.fbcdn.net/hphotos-xpa1/...jpg",

            "width": 213

        },

        {

            "height": 225,

            "source": "https://scontent-b.xx.fbcdn.net/hphotos-xpa1/...jpg",

            "width": 369

        }

    ],

    "link": "https://www.facebook.com/photo.php?fbid=...&set=...&type=1",

    "name": "Budapest Parlement - all rights reserved by @Christophe Nasarre",

    "picture": "https://scontent-b.xx.fbcdn.net/hphotos-xpa1/...jpg",

    "source": "https://scontent-b.xx.fbcdn.net/hphotos-xpa1/...jpg",

    "updated_time": "2014-07-27T09:56:02+0000",

    "width": 720

}

In addition to its name, you get its dimension with the width and height fields. Facebook keeps track of different sizes of each photo and the images Json list contains, sorted by decreasing dimensions, all these instances with the source url from which getting the corresponding image. I will keep only the first one which is the bigger one but for performance sake, UI responsiveness and limiting memory consumption, you should pick the url for the dimension that fits your needs.

 

I’ve left a last fundamental piece of information for the end: how to handle chunks of photos? Facebook is returning photos (but also albums) only group by group. The end of the data package contains a paging section with cursors that lists the before (previous) and after (next) page (URIs)

image

If there is no previous than you are on the first page and if there is no next, then… you are on the last page. The before and after values are used in the query to ask a particular batch of photos. As you can see in the screenshot, the next URI end with &after=<after value>; i.e. NzIwMjY1MzU0NjcyNTky. For a given batch of photos, the C# code is keeping track of the before and after values to be able to rebuild the query corresponding to the previous or next batch.

async public Task<PhotoBatch> GetAlbumPhotosAsync(string albumId, string navigationSuffix)

{

    PhotoBatch batch = newPhotoBatch(albumId);

    try

    {

        string path;

        if (string.IsNullOrEmpty(navigationSuffix))

        {

            path = string.Format("{0}/photos", albumId);

        }

        else

        {

            path = string.Format("{0}/photos?pretty=1&limit=25&{1}", albumId, navigationSuffix);

        }

 

        dynamic photosTaskResult = await FbClient.GetTaskAsync(path);

        var result = (IDictionary<string, object>)photosTaskResult;

Also note that the limit part of the query string allows you to set the number of photos that will be retrieved from Facebook.

The next and previous URIs are stored to easily figure out via binding if there is such a next or previous page to enable or disable the buttons.

<Button Name="btnPrevious" Content="Previous" IsEnabled="{Binding HasPrevious}"

<Button Name="btnNext" Content="Next" IsEnabled="{Binding HasNext}"

The data context is set to the current photo batch

public class PhotoBatch

{

    public string Id { get; set; }

    public List<Photo> Photos { get; set; }

    public string Before { get; set; }

    public string PreviousUri { get; set; }

    public bool HasPrevious

    {

        get

        {

            return !string.IsNullOrEmpty(PreviousUri);

        }

    }

    public string After { get; set; }

    public string NextUri { get; set; }

    public bool HasNext

    {

        get

        {

            return !string.IsNullOrEmpty(NextUri);

        }

    }

    public PhotoBatch(string id)

    {

        Id = id;

        Photos = newList<Photo>();

    }

}

The photos are stored in the C# Photo class

public class Photo

{

    public string Id { get; set; }

    public string Name { get; set; }

    public Int64 Width { get; set; }

    public Int64 Height { get; set; }

    public Uri LinkToImage { get; set; }

    public BitmapImage Image { get; set; }

}

And, like the albums case, in a second step,

private void UpdateAlbumPhotos(PhotoBatch batch)

{

    // update the UI

    gridPhotos.DataContext = batch;

    gvPhotos.ItemsSource = batch.Photos;

 

    // asynchronously fetch each photo

    foreach (var photo in batch.Photos)

    {

        photo.Image = newBitmapImage(photo.LinkToImage);

    }

}

the real pictures bits are downloaded asynchronously by the BitmapImage bound to the Image Source property:

image

 

Happy coding!