Thursday, March 05, 2009

Upload Photos using Flickr API in .NET

You know there is Flickr, and you know they provide free API Service for accessing the online photos repository programmatically. Now let us see how easy it is to use those APIs in .NET.

In this example I am creating a .NET 2.0 Windows Forms Application (I used Visual Studio 2008) in C# to upload a photo to your Flickr account and then create a new set (album) and assign that photo to this set.

Here are the steps to do this:

  • Get the API Key from Flickr (This key and its secret code are required to access the service)
    • Go to Your API Keys section on Flickr.
    • Click on ‘Apply for a new key online’ link.
    • Complete the process. I used the Non-Commercial option to get the key immediately. You will have to provide the details of your application. Once this is done, click on Edit key details and update all the information.
    • Note down the Key (it will look like 3e1f3c83c5e92ead353be33162fr4883) and Shared Secret (it will look like 700f4d5220833d34)
  • Get the FlickrNet API Library (This is a .NET wrapper class library around Flickr API and makes it very easy to call the services)
    • Go to http://flickrnet.codeplex.com/
    • Download either just the binaries or the source code if you would like to debug into the library.
    • FlickrNet.dll is the only one file you will require.
  • Design the application interface
    • I created a WinForm application as shown below with options to authenticate the user and to choose a picture file for uploading.

FlickrTest Now let us understand some theories behind Flickr API before we get into coding. Skip this if all you bother is to get your code working. :)

You need to do an authentication to the flickr account you are trying to access. This is a one time process and is done by directing the user to a URL (generated using the service) which will then open up in a browser. This process is initiated using ‘Start Auth’ button. Once the user logs into the flickr account and approve the access request from this application, he or she will have to come back to this application and click on ‘Complete Auth’. In this method, we get a ‘Token’ which uniquely identifies the user. This token can be saved and used again to access this user’s account without requiring further authentication process.

  • Add code to call Flickr API methods

First thing is to add a reference to the FlickrNet (either direct dll or the project reference if you use source code) in your project. Next declare the required variables.

private string flickrFrob = "";
private long fileSize = 1;
FlickrNet.Flickr myFlickr;

Then in the Form’s load event, provide your API Key and Share Secret codes and create the Flickr object. Event handlers are also added here.


private void MainForm_Load(object sender, EventArgs e)
{
uxKey.Text = "3e1f3c83c5e92ead353be33162fr4883";
uxSecret.Text = "700f4d5220833d34";
myFlickr = new FlickrNet.Flickr(uxKey.Text, uxSecret.Text);
uxOpen.Click += new EventHandler(uxOpen_Click);
uxAuthStart.Click += new EventHandler(uxAuthStart_Click);
uxAuthComplete.Click += new EventHandler(uxAuthComplete_Click);
uxUpload.Click+=new EventHandler(uxUpload_Click);
myFlickr.OnUploadProgress += new FlickrNet.Flickr.UploadProgressHandler(myFlickr_OnUploadProgress);
}

Now let us open an image for uploading…


void uxOpen_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Pictures|*.jpg";
if (ofd.ShowDialog() == DialogResult.OK)
{
uxFile.Text = ofd.FileName;
fileSize = ofd.OpenFile().Length;
Image img = Image.FromFile(ofd.FileName);
uxPicture.Image = img;
}
}

and then start authentication.


void uxAuthStart_Click(object sender, EventArgs e)
{
flickrFrob = myFlickr.AuthGetFrob();
string url = myFlickr.AuthCalcUrl(flickrFrob, FlickrNet.AuthLevel.Write);
System.Diagnostics.Process.Start(url);
}

This uses something called Frob (cookie kinda stuff) and generates a URL which is then opened up in the user’s default browser. Remember, at this point, user will have to sign in and authenticate the access request from this application.

Once the user completes the authentication and comes back to the application, we gets the token for that user.


void uxAuthComplete_Click(object sender, EventArgs e)
{
try
{
FlickrNet.Auth auth = myFlickr.AuthGetToken(flickrFrob);
myFlickr.AuthToken = auth.Token;
uxToken.Text = auth.Token;
uxUser.Text = auth.User.UserId;
}
catch (FlickrNet.FlickrException ex)
{
MessageBox.Show("User didn't approve!\n\n" + ex.Message);
}
}

The token is assigned to the Flickr object to enable access to that user’s account. It can be saved for later use without doing this authentication process again.

Now we are all set to upload the picture to flickr.


private void uxUpload_Click(object sender, EventArgs e)
{
uxProgress.Maximum = Convert.ToInt32(fileSize / 1000);
uxProgress.Value = 0; try
{
FlickrNet.Photo p = new FlickrNet.Photo();
System.Threading.Thread threadUpload = new System.Threading.Thread(delegate()
{
p.PhotoId = myFlickr.UploadPicture(uxFile.Text, "Sample Title", "Sample Description", "Sample Tag", false, false, true);
p.UserId = uxUser.Text;
FlickrNet.Photoset mySet = myFlickr.PhotosetsCreate("New Photoset", p.PhotoId);
System.Diagnostics.Process.Start(p.WebUrl);
}); threadUpload.Start();
}
catch (Exception ex)
{
MessageBox.Show("Upload failed!\n\n" + ex.Message);
}
}

Here we set the progress bar values and then use a new thread different from UI thread to call the Upload method. We also create a new photo set and add this photo to it.

The last thing is to make sure that the progress bar is updated properly.


private void myFlickr_OnUploadProgress(object sender, FlickrNet.UploadProgressEventArgs e)
{
if (e.UploadComplete)
{
this.Invoke((MethodInvoker)delegate()
{
uxProgress.Value = 0;
});
}
else
{
this.Invoke((MethodInvoker)delegate()
{
uxProgress.Value = e.Bytes / 1000;
});
}
}

That’s it… Hope this was useful to you and as always, feel free to ask any questions you may have on this…

12 comments:

  1. Who knows where to download XRumer 5.0 Palladium?
    Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!

    ReplyDelete
  2. Hi. What component did you use to get the path of the photo in front of your "upload" button?

    ReplyDelete
  3. Where do we "declare the required variables"?

    private string flickrFrob = "";
    private long fileSize = 1;
    FlickrNet.Flickr myFlickr;

    ReplyDelete
  4. Robert,

    1. OpenFileDialog will get you the path of the photo, when you open an image from your local computer.

    2. Variables are declared at the class level in MainForm class, just after the class name.

    ReplyDelete
  5. Thank you Sameer.

    I'm also getting an exception throw here:

    try
    {
    FlickrNet.Auth auth = myFlickr.AuthGetToken(flickrFrob);
    myFlickr.AuthToken = auth.Token;
    uxToken.Text = auth.Token;
    uxUser.Text = auth.User.UserId;
    }
    catch (FlickrNet.FlickrException ex)
    {
    MessageBox.Show("User didn't approve!\n\n" + ex.Message);
    }

    Any ideas? I click the "Start Auth" button and the page opens to my flickr account to which I give the application access. Upon returning to the application an exception gets thrown saying "Invalid frob (108)" and that the "User didn't approve!". Any advice/ideas? Thanks.

    ReplyDelete
  6. Not sure about this, Robert. Make sure cookies are enabled in your browser.

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. Fantastic example. However, the FlickrNet.Flickr.UploadProgressHandler delegate is not found. Has that been deprecated? The compile error I see is "The type name 'UploadProgressHandler' does not exist in the type 'FlickrNet.Flickr'

    ReplyDelete
  9. Hey i want to use it for windows phone 7 development. please help.

    ReplyDelete
  10. can u help me in writing c# code for getting an particular image from flickr...like we will pass the keyword and it will display all the images withj that keyword

    ReplyDelete
  11. This comment has been removed by the author.

    ReplyDelete