65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 ASP.NET 2.0 构建简单图片库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (17投票s)

2006年5月30日

7分钟阅读

viewsIcon

321589

downloadIcon

12965

一篇关于创建简单、易于维护且美观的照片库的文章。

Sample Image - Nileblitz_Photo_Gallery.jpg

引言

前一阵子,我花了相当多的时间在网上寻找我心目中完美的图片库。我尝试了网上已有的各种解决方案,但由于这样或那样的原因,我无法让它们满足我的需求。

  • 我需要一个“开箱即用”的图片库。你所需要做的就是将几张图片放到一个文件夹中,仅此而已。
  • 这个图片库还需要美观。
  • 这个图片库应该易于使用。

我决定自己尝试一下。我相信,在一个周末内,我创建了一个满足我所有需求的东西。希望它也能满足你的需求。

步骤 1

第一步是在 Visual Studio .NET 2005 中创建一个“新建网站...”项目。创建完成后,你将拥有一个 Default.aspx 文件和一个 web.config 文件。在根目录中创建一个 PicStore 文件夹。这个文件夹将用于存放你的图片库。

PicStore 文件夹中,创建一个 Default 子文件夹。我们创建此文件夹是为了表示默认的图片库集合。这是为了将来,当我计划扩展应用程序以包含我朋友的图片库时。他们的图片库将位于其他文件夹中,但当用户首次浏览应用程序时,将加载 Default 图片库集合。

Default 文件夹中,创建你的图片库。为了本文的缘故,我建议创建 Photogallery 1Photogallery 2 等。在每个图片库中,创建一个 pics 文件夹。此文件夹将用于存放你的图片。

注意

  1. 只接受 JPG 文件格式。
  2. 照片**必须**以 001.JPG002.JPG003.JPG 等模式命名。
  3. 如果你想为任何照片添加标题,请将其重命名为 00X~Title_With_Underscores_For_Spaces.JPG 的模式,其中 X 是照片的编号。

这个图片库设计用于清晰地显示最大宽度为 750 像素的图片。当然,你可以放置更大或更小的图片,但你需要相应地调整背景。我建议所有图片保持相同的最大宽度。你可以使用免费工具 Irfanview 批量将所有图像格式化为特定大小。在“批量转换 > 高级选项”中有一个选项可以将所有图像的长边设置为特定大小。这完美地符合了我的要求。

或者,如果你希望用户能够看到图片的缩略图而不是导航中的图像名称,你还可以在 pics 文件夹旁边创建一个兄弟文件夹 thumbs。我建议你的缩略图长边应限制为 100 像素。

我的示例代码中提供了一些图像,如 arrow2.gifbg.gif 等。你可以下载这些并将它们放到项目根目录中相应的文件夹中,或者,从代码中删除对它们的引用。

我们最后要做的是将键 `PicRootPath` 和 `PicRootDefaultPath` 添加到 web.config 中,如下所示

<appSettings>
    <add key="PicRootPath" value="~/PICStore/"/>
    <add key="PicRootDefaultPath" value="~/PicStore/Default/" />
</appSettings>

以上是项目的准备工作。现在,我们将添加图片库的代码。

第二步

现在,如果项目中不存在 App_Code 文件夹,我们就创建一个。在其中,我们将创建一个名为 `ContentInfoLoader` 的类。这个类将负责为我们的应用程序加载图片库和照片的信息。我们类的构造函数将加载图片库的根路径和默认的图片库集合。以下是其代码

Configuration rootWebConfig = 
    WebConfigurationManager.OpenWebConfiguration("~/");
if(0<rootWebConfig.AppSettings.Settings.Count)
{
    KeyValueConfigurationElement picRootElement = 
        rootWebConfig.AppSettings.Settings["PicRootPath"];
    if(null!=picRootElement)
    {
        _picRootPath=picRootElement.Value;
    }

    picRootElement = rootWebConfig.AppSettings.Settings["PicRootDefaultPath"];
    if (null != picRootElement)
    {
        _picRootDefaultPath = picRootElement.Value;
    }
}

路径存储在私有变量中,可以通过只读属性访问。现在我们创建一个简单的方法来获取我们集合中可用的图片库列表。以下是其代码

public string[] GetGalleryPaths(string picRootRealPath) 
{
    if (Directory.Exists(picRootRealPath))
    {
        return Directory.GetDirectories(picRootRealPath);
    }
    else
    {
        return null;
    }
}

如你所见,此方法接受图片根目录的路径(可以是默认路径或任何其他路径),并返回一个包含图片库路径的 string 数组。请注意,这些是物理路径。我们需要创建另一个方法来获取当前选定图片库中每张照片的列表。以下是执行此操作的代码

public string[] GetPhotoList(string galleryName, string picRootRealPath)
{
    string galleryPath=picRootRealPath + "\\" + galleryName + "\\pics";
    if (Directory.Exists(galleryPath))
    {
        return Directory.GetFiles(galleryPath,"*.JPG");
    }
    else
    {
        return null;
    }
}

请注意,此方法接受图片库的名称和根路径。它返回包含其物理路径的照片列表。

步骤 3

现在我们创建一个母版页来配合我们的图片库应用程序页面。

首先,我建议删除项目自动创建的 Default.aspx 文件。接下来,在解决方案资源管理器中右键单击项目,然后单击“添加新项...”。选择“母版页”并将其命名为 SuperMasterPage.master。在母版页中,紧随 body 标签之后添加以下 JavaScript 代码

<script type="text/javascript">

    var offsetfromcursorX=12 //Customize x offset of tooltip

    var offsetfromcursorY=10 //Customize y offset of tooltip


    //Customize x offset of tooltip DIV relative to pointer image

    var offsetdivfrompointerX=10
    //Customize y offset of tooltip DIV relative 

    //to pointer image. Tip: Set it to 

    //(height_of_pointer_image-1).

    var offsetdivfrompointerY=7

    //write out tooltip DIV

    document.write('<div id="dhtmltooltip"></div>')
    //write out pointer image

    document.write('<img id="dhtmlpointer" ' + 
        'src="https://codeproject.org.cn/SourceCode/images/arrow2.gif">')

    var ie=document.all
    var ns6=document.getElementById && !document.all
    var enabletip=false
    if (ie||ns6)
    var tipobj=document.all? document.all["dhtmltooltip"] : 
        document.getElementById? 
        document.getElementById("dhtmltooltip") : ""

    var pointerobj=document.all? document.all["dhtmlpointer"] : 
        document.getElementById? 
        document.getElementById("dhtmlpointer") : ""

    function ietruebody()
    {
        return (document.compatMode && document.compatMode!="BackCompat")? 
            document.documentElement : document.body
    }

    function ddrivetip(thetext, thewidth, thecolor)
    {
        if (ns6||ie)
        {
            if (typeof thewidth!="undefined")
                tipobj.style.width=thewidth+"px"
            if (typeof thecolor!="undefined" && thecolor!="")
                tipobj.style.backgroundColor=thecolor
                tipobj.innerHTML=thetext
                enabletip=true
                return false
        }
    }

    function positiontip(e)
    {
        if (enabletip)
        {
            var nondefaultpos=false
            var curX=(ns6)?e.pageX : event.clientX+ietruebody().scrollLeft;
            var curY=(ns6)?e.pageY : event.clientY+ietruebody().scrollTop;
            //Find out how close the mouse is to the corner of the window

            var winwidth=ie&&!window.opera? ietruebody().clientWidth : 
                window.innerWidth-20
            var winheight=ie&&!window.opera? 
                ietruebody().clientHeight : window.innerHeight-20
            var rightedge=ie&&!window.opera? 
                winwidth-event.clientX-offsetfromcursorX : 
                winwidth-e.clientX-offsetfromcursorX
            var bottomedge=ie&&!window.opera? 
                winheight-event.clientY-offsetfromcursorY : 
                winheight-e.clientY-offsetfromcursorY
            var leftedge=(offsetfromcursorX<0)? 
                offsetfromcursorX*(-1) : -1000

            //if the horizontal distance isn't enough to 

            //accomodate the width of the context menu

            if (rightedge<tipobj.offsetWidth)
            {
                //move the horizontal position of 

                //the menu to the left by it's width

                tipobj.style.left=curX-tipobj.offsetWidth+"px"
                nondefaultpos=true
            }
            else if (curX<leftedge)
                tipobj.style.left="5px"
            else
            {
                //position the horizontal position of 

                //the menu where the mouse is positioned

                tipobj.style.left=curX+offsetfromcursorX-
                    offsetdivfrompointerX+"px"
                pointerobj.style.left=curX+offsetfromcursorX+"px"
            }

            //same concept with the vertical position

            if (bottomedge<tipobj.offsetHeight)
            {
                tipobj.style.top=curY-tipobj.offsetHeight-
                    offsetfromcursorY+"px"
                nondefaultpos=true
            }
            else
            {
                tipobj.style.top=curY+offsetfromcursorY+
                    offsetdivfrompointerY+"px"
                pointerobj.style.top=curY+offsetfromcursorY+"px"
            }
            tipobj.style.visibility="visible"
            if (!nondefaultpos)
                pointerobj.style.visibility="visible"
            else
                pointerobj.style.visibility="hidden"
        }
    }

    function hideddrivetip()
    {
        if (ns6||ie)
        {
            enabletip=false
            tipobj.style.visibility="hidden"
            pointerobj.style.visibility="hidden"
            tipobj.style.left="-1000px"
            tipobj.style.backgroundColor=''
            tipobj.style.width=''
        }
    }

    document.onmousemove=positiontip

</script>

此 JavaScript 代码将用于显示工具提示,以显示图片库名称和缩略图。

**注意:** 无论你在代码中看到“/SourceCode/”的地方,请将其替换为你的应用程序所在的“虚拟目录”。如果你将其创建在机器网站的根目录中,则在必要时删除 /SourceCode/

步骤 4

现在我们需要创建实际的图片库显示页面,以便它可以使用我们上面创建的类。右键单击你的项目,然后单击“添加新项...”选择“Web 窗体”,并确保选中“将代码放在单独的文件中”和“选择母版页”复选框。打开 PicViewer.aspx 源文件。你将看到一个 asp:content 标签。在此标签内,放置以下代码

<table width="760px" cellpadding="1" cellspacing="0">
    <tr>
        <td colspan="5"><asp:PlaceHolder ID="galleryPlaceholder" 
            runat="server"></asp:PlaceHolder>
        </td>
    </tr>
    <tr>
        <td bgcolor="#494949" width="700px">
            <asp:Label ID="lblGalleryName" runat="server" 
                CssClass="SubHeadingWhite">&#9660; How to use</asp:Label>
        </td>
        <td bgcolor="#494949"></td>
        <td bgcolor="#494949"><asp:Label ID="lblPhotoName" 
            runat="server" CssClass="SubTitleWhite"></asp:Label></td>
    </tr>
    <tr>
        <td align="center" colspan="5"><asp:Image ID="galleryImage" 
            runat="server" BorderStyle="Solid" 
            BorderWidth="5px" BorderColor="Black" />
        </td>
    </tr>
</table>

上述代码放置了一个名为 `galleryPlaceholder` 的占位符,我们稍后将向其中添加图片库和照片导航栏。除此之外,你还可以看到标签,它将显示图片的标题(如果有),否则显示图片的编号。

当 PicViewer 页面加载时,我们加载图片库的导航。如果这是第一次(没有显示图片库),我们显示 Howtouse.jpg 说明照片。如果这不是第一次,即用户单击了某个图片库,我们显示第一张图片。如果用户单击了某张图片,我们显示图片和标题。以下是 `Page_Load` 子例程的代码

protected void Page_Load(object sender, EventArgs e)
{
    ContentInfoLoader cil = new ContentInfoLoader();
    string galleriesPath = "";
    if (Session["PicRootPath"] != null && 
        Session["PicRootPath"].ToString() != "")
    {
        galleriesPath = Session["PicRootPath"].ToString();
    }
    else
    {
        galleriesPath = cil.PicRootDefaultPath;
        Session["PicRootPath"] = galleriesPath;
    }
     
    LoadGalleriesNav(galleriesPath,cil);
    if (Request["gallery"] != "" && Request["gallery"] != null)
    {
        lblGalleryName.Text = Request["gallery"];
        Int32 photoCount = 
            LoadPhotosNav(Request["gallery"], galleriesPath, cil);
        string photoName;
        if (Request["photo"] == "" || Request["photo"] == null)
        {
            //If the user has just clicked on

            //the gallery, load the first photo

            photoName = cil.GetPhotoList(Request["gallery"], 
                Server.MapPath(galleriesPath))[0];
            photoName = photoName.Substring(photoName.LastIndexOf("\\"));
        }
        else
        {
            //Otherwise load the photo as in the querystring
            photoName = Request["photo"];
        }
        char[] charSeparators = new char[] { '~', '.' };
        if (photoName.Contains("~"))
        {
            string photoTitle = photoName.Split(charSeparators)[1];
            lblPhotoName.Text = photoTitle.Replace("_", " ");
        }
        else
        {
            lblPhotoName.Text = photoName.Split(charSeparators)[0];
        }
        galleryImage.ImageUrl = galleriesPath + 
            Request["gallery"] + "/pics/" + photoName;
    }
    else
    {
        galleryImage.ImageUrl = galleriesPath + "Howtouse.jpg";
    }
}

图片库和照片的导航基本上是使用 CSS 格式化的无序列表。图片库列表和照片列表之间存在一些主要差异,除了明显的尺寸、形状和颜色之外

  • 图片库列表,当我们鼠标悬停时,我们会看到图片库的名称。
  • 照片列表,当我们鼠标悬停时,如果 `thumbs` 目录不存在,我们看到标题;否则,我们看到缩略图和标题。

在两种导航中,如果选择了某个图片库或选择了某个图片库和一张照片,这些项目将变灰且无法选择。除此之外,大部分代码都非常简单且不言自明。如果需要进一步解释,请告诉我。以下是代码

/// <summary>

/// This method is supposed to load the navigation for the galleries

/// </summary>

public void LoadGalleriesNav(string galleriesPath, ContentInfoLoader cil)
{
    string[] galleryPathList = new string[1];

    // Load the path info for all the galleries

    if (galleriesPath != "")
    {
        galleryPathList = 
            cil.GetGalleryPaths(Server.MapPath(galleriesPath));
    }

    // Generate the unordered list

    HtmlGenericControl blstGalleries = new HtmlGenericControl("ul");
    blstGalleries.Attributes.Add("id", "navlist_a");

    // Generate the navigation for the galleries

    foreach (string galleryPath in galleryPathList)
    {
        string galleryName = 
            galleryPath.Substring(galleryPath.LastIndexOf("\\") + 1);
        HtmlGenericControl galleryListItem = new HtmlGenericControl("li");
        HtmlAnchor galleryAnchor = new HtmlAnchor();
        if (Request["gallery"] != "" && Request["gallery"] != null)
        {
            // If the gallery has not been chosen, generate a link
            if (Request["gallery"].ToUpper() != galleryName.ToUpper())
            {
                galleryAnchor.Attributes.Add("onMouseOver", "ddrivetip('" + 
                    galleryName.ToUpper() + "', " + 
                    galleryName.Length * 7 + ")");
                galleryAnchor.Attributes.Add("onMouseOut", "hideddrivetip()");
                galleryAnchor.HRef = "PicViewer.aspx?gallery=" + galleryName;
                galleryAnchor.InnerHtml = "<em></em>";
            }
            else
            {
                // if a gallery has been chosen
                // already then gray out the selection
                galleryAnchor.Disabled = true;
                galleryAnchor.InnerHtml = "<em style='border-top" + 
                    ":1em solid #696969'></em>";
            }
        }
        else
        {// If the gallery has not been chosen, generate a link
            galleryAnchor.Attributes.Add("onMouseOver", "ddrivetip('" + 
                galleryName.ToUpper() + "', " + 
                galleryName.Length * 7 + ")");
            galleryAnchor.Attributes.Add("onMouseOut", "hideddrivetip()");
            galleryAnchor.HRef = "PicViewer.aspx?gallery=" + galleryName;
            galleryAnchor.InnerHtml = "<em></em>";
        }
        // add the anchor to the list
        galleryListItem.Controls.Add(galleryAnchor);
        blstGalleries.Controls.Add(galleryListItem);
    }
    galleryPlaceholder.Controls.Add(blstGalleries);
}


/// <summary>
/// Load the navigation for the photos
/// </summary>
public Int32 LoadPhotosNav(string galleryName, 
    string galleriesPath, ContentInfoLoader cil)
{
    string[] photoList = new string[1];
    if (galleriesPath!= "")
    {
        photoList = cil.GetPhotoList(galleryName, 
            Server.MapPath(galleriesPath));
    }
    if (photoList != null && photoList.Length != 0)
    {
        HtmlGenericControl blstPhotos = new HtmlGenericControl("ul");
        blstPhotos.Attributes.Add("id", "navlist_b");

        foreach (string iPhotoName in photoList)
        {
            string photoName;
            photoName = 
                iPhotoName.Substring(iPhotoName.LastIndexOf("\\") + 1);
            HtmlGenericControl photoListItem = new HtmlGenericControl("li");
            HtmlAnchor photoAnchor = new HtmlAnchor();
            string originalPhotoName = photoName;
            char[] charSeparators = new char[] { '~','.' };
            string photoTitle = "";
            if (photoName.Contains("~"))
            {
                photoTitle = photoName.Split(charSeparators)[1];
                photoName = photoName.Split(charSeparators)[0] + ".JPG";
            }

            if (Request["photo"] != "" && Request["photo"] != null)
            {
                // if a photo has been selected then we need
                // to show that square as gray otherwise
                // clickable and mouseover effects.
                if (Request["photo"].ToUpper() != photoName.ToUpper())
                {
                    if (Directory.Exists(Server.MapPath(galleriesPath + 
                        galleryName + "/thumbs/")))
                    {
                        photoAnchor.Attributes.Add("onMouseOver", 
                            "ddrivetip('<img src=\\'" + 
                            ResolveUrl(galleriesPath) + galleryName + 
                            "/thumbs/" + photoName + 
                            "\\' /><br>" + 
                            photoTitle.Replace("_", " ") + "', " + 
                            photoTitle.Length + ")");
                    }
                    else
                    {
                        if (photoTitle != "")
                        {
                            photoAnchor.Attributes.Add("onMouseOver", 
                                "ddrivetip('" + photoTitle.Replace("_", 
                                " ") + "', " + photoTitle.Length + ")");
                        }
                        else
                        {
                            photoAnchor.Attributes.Add("onMouseOver", 
                                "ddrivetip('" + photoName + "', " + 
                                photoName.Length + ")");
                        }
                    }

                    photoAnchor.Attributes.Add("onMouseOut", 
                        "hideddrivetip()");
                    photoAnchor.HRef = "PicViewer.aspx?gallery=" + 
                        galleryName + "&photo=" + originalPhotoName;
                    photoAnchor.InnerHtml = "<em></em>";
                }
                else
                {
                    photoAnchor.Disabled = true;
                    photoAnchor.InnerHtml = "<em style='border-top" + 
                        ":0.5em solid #696969'></em>";
                }
            }
            else
            {
                if (Directory.Exists(Server.MapPath(galleriesPath + 
                    galleryName + "/thumbs/")))
                {
                    photoAnchor.Attributes.Add("onMouseOver", 
                        "ddrivetip('<img src=\\'" + 
                        ResolveUrl(galleriesPath) + 
                        galleryName + "/thumbs/" + photoName + 
                        "\\' /><br>" + photoTitle.Replace("_", 
                        " ") + "', " + photoTitle.Length + ")");
                }
                else
                {
                    if (photoTitle != "")
                    {
                        photoAnchor.Attributes.Add("onMouseOver", 
                            "ddrivetip('" + 
                            photoTitle.Replace("_", " ") + "', " + 
                            photoTitle.Length + ")");
                    }
                    else
                    {
                        photoAnchor.Attributes.Add(
                            "onMouseOver", "ddrivetip('" + 
                            photoName + "', " + photoName.Length + ")");
                    }
                }

                photoAnchor.Attributes.Add("onMouseOut", "hideddrivetip()");
                photoAnchor.HRef = "PicViewer.aspx?gallery=" + galleryName + 
                                   "&photo=" + originalPhotoName;
                photoAnchor.InnerHtml = "<em></em>";
            }
            photoListItem.Controls.Add(photoAnchor);
            blstPhotos.Controls.Add(photoListItem);
        }
        galleryPlaceholder.Controls.Add(blstPhotos);
        return photoList.Length;
    }
    else
    {
        return 0;
    }
}

应用程序现在已准备好进行测试。

如何安装演示/源代码

请注意,你必须安装 .NET Framework 2.0,并且你的网站应设置为使用 ASP.NET 2.0 (IIS 网站属性)。

  • 在你的 IIS 上创建一个名为 SourceCode 的虚拟目录。
  • demo/sourcecode 的内容解压到相应的物理文件夹中。

已知问题

已知问题如下

  • 一个图片库中不能添加超过 999 张照片。
  • 图片库加载时,第一张照片的导航方块未变灰。
  • 你无法提供照片的描述,只能提供标题。
  • 没有用户友好的照片上传工具。

我确信还有其他需要修改的地方或需要添加的其他功能。请告诉我。

最后...

随着应用程序的升级,我也会升级本文。所以,请关注此空间。欢迎向我发送你对此文章的评论。请告诉我这篇文章是否对你有帮助,或者是否需要改进。

© . All rights reserved.