In this post I will give one way, or my take on how-to integrate
an external photo gallery seamless in to your website. Some of the
advantage in doing this is you save room/space on your local
webhost, and the load on the serve if you have large photo/images
since these are not load in another thread on an external server.
Off course there are disadvantage as well the gallery provide have
to be online for this to work, and you have to maintain gallery
content and web content on two different websites. On the other
hand you if you choose one of the large providers flickr or picasa,
you get some great photo gallery functionality tagging of images
and galleries and more.
So i don't what to build the new Picasa or a like, so i will
only provide functionality for showing frontend relevant images and
associated information. In near future there will be a post on
how-to use this post to integrate into Umbraco.
For this post i have chosen to integrate up against Google's
Picasa so to start with you can go and download the google-gdata
API you can get it here
The documentation i used to for making this post and code can be
found here
The main idea for making this seamless is it could be easy to
switch gallery provider from picasa to whatever your favorite
web-photo gallery you use. Off course the difficulties you meet
depend on how well an interface the provider gives you, you could
end up in some tricky situations.
Okay let's get started. First of I've created the interfaces I've
so necessary for making a good web gallery. You are more than
welcome to give feedback if you think something are missing on one
these.
There exist three parts. A gallery which consists of one or more
photo albums. Next there off course a photo album which contain
some album information and one or more Images. Last off is the
image it self. So here are the three interfaces.
public interface IGallery
{
String Name { get; }
String Description { get; }
int NumberOfAlbums { get; }
IEnumerable Albums{get;}
IGalleryAlbum GetAlbumFromId(string id);
}
public interface IGalleryAlbum
{
String Id { get; }
String Name{ get; }
String Description { get; }
String Category { get; }
IGalleryImage AlbumCoverImage { get; }
uint NumberOfImages { get; }
IEnumerable Images { get; }
}
public interface IGalleryImage
{
String Name { get; }
String Url { get; }
String Description { get; }
String ThumbnailUrl { get; }
Dictionary ExifData { get; }
}
Again you are more than welcome to give feedback if you think
something is missing, keep in mind this is what I think is one a
good and simple image gallery should be able to provide of
information.
So now we have the interfaces in place lets go ahead an implement
them using the Picasa API.
This is a pretty simple task if keep a window open with the
documentation here is another link to the documentation
All I've used is the simple example provide at the documentation
page.
First of the gallery implementation this is simple
namespace PicasaGalleryModel
{
public class PicasaGallery : IGallery
{
private PicasaService _service;
private PicasaFeed _feed;
private const string PICASA_SERVICE_NAME = "PicasaIGalleryModel";
public PicasaGallery(string username)
{
Username = username;
}
public string Name
{
get
{
return Feed.Title.Text;
}
}
public string Description
{
get { return ""; }
}
public int NumberOfAlbums
{
get { return Albums.Count(); }
}
public IEnumerable Albums
{
get
{
return InitializeGalleryAlbumFromPicasaFeed();
}
}
public IGalleryAlbum GetAlbumFromId(string id)
{
return Albums.Where(g => g.Id == id).First();
}
private PicasaFeed Feed
{
get
{
if (_feed == null)
_feed = RetrieveUserAlbumsFromPicasa();
return _feed;
}
}
private PicasaFeed RetrieveUserAlbumsFromPicasa()
{
AlbumQuery query = new AlbumQuery(PicasaQuery.CreatePicasaUri(Username));
PicasaFeed feed = Service.Query(query);
return feed;
}
private IEnumerable InitializeGalleryAlbumFromPicasaFeed()
{
foreach (PicasaEntry entry in Feed.Entries)
{
IGalleryAlbum album = new PicasaAlbum(entry,Service,Username);
yield return album;
}
}
private PicasaService Service
{
get
{
if(_service == null)
_service = new PicasaService(PICASA_SERVICE_NAME);
return _service;
}
}
private void Logon()
{
}
protected string Password
{
get;
set;
}
protected string Username
{
get; set ;
}
}
}
DO note that the username is the logon name you use to logon to
picasa.
The implementation have some unused and unfinished function, when
I first the idea to this post it started as huge project where I
wanted security from picasa as well to be covered, in this
implementation.
Wow this class uses the IGalleryAlbum so let's move on to the
implantation of this.
namespace PicasaGalleryModel
{
public class PicasaAlbum : IGalleryAlbum
{
private PicasaEntry _albumFeed;
private PicasaFeed _imageFeed;
private AlbumAccessor _ac;
public PicasaAlbum(PicasaEntry feed,PicasaService service,string username)
{
AlbumFeed = feed;
Service = service;
Username = username;
}
public string Name
{
get { return AlbumAccessor.AlbumTitle; }
}
public string Description
{
get { return AlbumAccessor.AlbumSummary; }
}
public string Category
{
get { return "CAT-SET_STATIC"; }
}
public IGalleryImage AlbumCoverImage
{
get
{
PhotoQuery query = PhotoQueryFromUri(AlbumFeed.Id.AbsoluteUri);
return BuildIGalleryImageFromPicasa(Service.Query(query)).First();
}
}
private AlbumAccessor AlbumAccessor
{
get
{
if (_ac == null)
_ac = new AlbumAccessor(AlbumFeed);
return _ac;
}
}
public uint NumberOfImages
{
get
{
return AlbumAccessor.NumPhotos;
}
}
public IEnumerable Images
{
get
{
return BuildIGalleryImageFromPicasa(ImageFeed);
}
}
private IEnumerable BuildIGalleryImageFromPicasa(PicasaFeed feed)
{
foreach (PicasaEntry entry in feed.Entries)
{
IGalleryImage image = new PicasaImage(entry);
yield return image;
}
}
public PicasaEntry AlbumFeed
{
get { return _albumFeed; }
set { _albumFeed = value; }
}
public PicasaFeed ImageFeed
{
get
{
if(_imageFeed == null)
{
_imageFeed = Service.Query(PhotoQueryFromUri(PicasaImageUri()));
}
return _imageFeed;
}
}
private string PicasaImageUri()
{
return PicasaQuery.CreatePicasaUri(Username, Id);;
}
private PhotoQuery PhotoQueryFromUri(string uri)
{
return new PhotoQuery(uri);
}
private PicasaService Service
{
get; set;
}
public String Id
{
get
{
return AlbumAccessor.Id;
}
}
private string Username
{
get;
set;
}
}
}
And now to the final part the Image implementation
namespace PicasaGalleryModel
{
public class PicasaImage : IGalleryImage
{
private PhotoAccessor _photoAccessor;
private Dictionary _exifData;
public PicasaImage(PicasaEntry entry)
{
Entry = entry;
}
private PicasaEntry Entry
{
get;
set;
}
public string Name
{
get
{
return PhotoAccessor.PhotoTitle;
}
}
public string Url
{
get
{
return Entry.Media.Content.Attributes["url"].ToString();
}
}
public string Description
{
get { return PhotoAccessor.PhotoSummary; }
}
public string ThumbnailUrl
{
get
{
return Entry.Media.Thumbnails[0].Attributes["url"].ToString();
}
}
public Dictionary ExifData
{
get
{
if (_exifData == null)
InitializeExifDataToDictionary();
return _exifData;
}
}
private void InitializeExifDataToDictionary()
{
_exifData = new Dictionary();
_exifData.Add("Camera model", Entry.Exif.Model.Value);
_exifData.Add("ISO", Entry.Exif.ISO.Value);
_exifData.Add("Focal Length", Entry.Exif.FocalLength.Value);
//_exifData.Add("Exposure", Entry.Exif.Exposure.Value);
_exifData.Add("F Stop", Entry.Exif.FStop.Value);
_exifData.Add("Flash", Entry.Exif.Flash.Value);
}
public PhotoAccessor PhotoAccessor
{
get
{
if(_photoAccessor == null)
_photoAccessor = new PhotoAccessor(Entry);
return _photoAccessor;
}
}
}
}
Now with the model in place we can start to render out the
IGallery* stuff.
This is made so it should be easy to integrate into Umbraco hence
the MasterPage file.
The frontend stuff consist of the main gallery which loads in two
different controls depending on you are viewing a list of albums or
a list images in an album. The styling is left for you do, since
this is dependent on your website design. If you like a can In a
later post do this.
The main gallery
The .ascx page
<%@ Page Language="C#" MasterPageFile="~/Gallery.master"
AutoEventWireup="true" CodeBehind="Default.aspx.cs"
Inherits="Presentation._Default" %>
<%@ Import Namespace="Interfaces" %>
<asp:Content ID="head" ContentPlaceHolderID="head"
Runat="Server">
<script type="text/javascript"
src="js/jquery.js"></script>
<script type="text/javascript"
src="js/jquery.lightbox-0.5.min.js"></script>
<script type="text/javascript"
src="js/InitLightbox.js"></script>
<link rel="stylesheet" type="text/css"
href="/CSS/jquery.lightbox-0.5.css" media="screen" />
</asp:Content>
<asp:Content ID="GalleryContent"
ContentPlaceHolderID="GalleryContent" Runat="Server">
<div>
My Gallery Test
<asp:PlaceHolder ID="galleryContent" runat="server" />
</div>
</asp:Content>
and the codepage
public partial class _Default : System.Web.UI.Page
{
private IGallery _gallery;
public const string ALBUMID = "aid";
protected void Page_Load(object sender, EventArgs e)
{
SetGalleryContent();
}
private void SetGalleryContent()
{
Control view;
if (String.IsNullOrEmpty(AlbumId))
view = LoadGalleryView;
else
view = LoadAlbumView;
galleryContent.Controls.Add(view);
}
private IEnumerable GalleryAlbums
{
get
{
return Gallery.Albums;
}
}
private Control LoadGalleryView
{
get
{
Control viewControl = LoadControl("~/GalleryView.ascx");
GalleryView gallery = (GalleryView)viewControl;
gallery.AlbumQueryString = ALBUMID;
gallery.GalleryAlbums = GalleryAlbums;
return viewControl;
}
}
private Control LoadAlbumView
{
get
{
Control viewControl = LoadControl("~/AlbumView.ascx");
AlbumView gallery = (AlbumView)viewControl;
gallery.Images = CurrentAlbum.Images ;
return viewControl;
}
}
private IGalleryAlbum CurrentAlbum
{
get
{
return Gallery.GetAlbumFromId(AlbumId);
}
}
private string AlbumId
{
get
{
return Request.QueryString[ALBUMID];
}
}
private IGallery Gallery
{
get
{
if(_gallery == null)
_gallery = new PicasaGallery("USERNAME_GOES_HERE");
return _gallery;
}
}
}
The List view of albums
Ascx page
<%@ Control Language="C#" AutoEventWireup="true"
CodeBehind="GalleryView.ascx.cs"
Inherits="Presentation.GalleryView" %>
<%@ Import Namespace="Interfaces"%>
<asp:Repeater runat="server" ID="AlbumeRepeater"
DataSource="<%# GalleryAlbums %>">
<ItemTemplate>
<div class="AlbumCoverImage">
<a href="<%#
AlbumLink(((IGalleryAlbum)Container.DataItem).Id) %>" >
<img src="<%#
((IGalleryAlbum)Container.DataItem).AlbumCoverImage.ThumbnailUrl
%>" alt="" />
</a>
</div>
<div class="AlbumTitle">
<a href="<%#
AlbumLink(((IGalleryAlbum)Container.DataItem).Id) %>" >
<%# ((IGalleryAlbum)Container.DataItem).Name %>
</a>
</div>
<div class="ImageCountInAlbum">
<%# ((IGalleryAlbum)Container.DataItem).NumberOfImages
%>
</div>
<div class="AlbumDescription">
<%# ((IGalleryAlbum)Container.DataItem).Description%>
</div>
</ItemTemplate>
</asp:Repeater>
Codepage
public partial class GalleryView : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
AlbumeRepeater.DataBind();
}
public string AlbumLink(string albumId)
{
string url = String.Format("{0}{1}={2}", Request.RawUrl, AlbumQueryString, albumId);
return url;
}
public string AlbumQueryString
{
get; set;
}
public IEnumerable GalleryAlbums
{
get;
set;
}
}
And finally the list view of images in an album
Ascx page
<%@ Control Language="C#" AutoEventWireup="true"
CodeBehind="AlbumView.ascx.cs" Inherits="Presentation.AlbumView"
%>
<%@ Import Namespace="Interfaces"%>
<asp:Repeater ID="ImageRepeater" runat="server"
DataSource="<%#Images %>">
<HeaderTemplate>
<ul id="Gallery">
</HeaderTemplate>
<ItemTemplate>
<li>
<a href="<%# ((IGalleryImage)Container.DataItem).Url %>"
class="lightbox" title="<%#
ExifData((IGalleryImage)Container.DataItem)%>"><img
src="<%# ((IGalleryImage)Container.DataItem).ThumbnailUrl %>"
/></a>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
codefile
public partial class AlbumView : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
ImageRepeater.DataBind();
}
public string ExifData(IGalleryImage image)
{
string exifData = "";
foreach(string key in image.ExifData.Keys)
{
exifData += string.Format("{0} : {1}
", key, image.ExifData[key]);
}
return exifData;
}
public IEnumerable Images
{
get;
set;
}
}
The final part is using the jquery lightbox again you could switch
this to you own favorite gallery viewing service the lightbox for
jquery can be found here. I've extend this a bit so you can provide
a max image height and max image width, both are found in the
solution for this project.
And a service for my loyal readers, you can now download the
entire solution which contains all the above models
implementations, and all the other good stuff I've covered in this
post. Now you can get HERE,
Rememer to fill out your own Username
And now you can head over and see when this is integrated into
umbraco, i've done this for my site here is a like to my gallery