Load SharePoint Web-optimized Images into a DVWP

Web Design & Development

It finally happened. I’m starting a SharePoint category on my blog.

So, I recently worked on a project in which users were encouraged to upload photos that they took at volunteer events around the country. The stakeholder wanted to have a slideshow of these images on the event home page, and of course it had to look good.

I immediately thought of using a Data View Web Part and some jQuery because I knew I could create a nice-looking slideshow using one of the many jQuery plugins available on the web. However, I wanted to make sure the images looked good and fit within the slide show’s boundaries.

Luckily for me SharePoint creates web-optimized and thumbnail versions of images when they are uploaded into a Picture Library (not to be confused with the standard “Images” document library that is created for a site with the Publishing feature enabled). The tricky part was getting those optimized versions to load on the page instead of the original images, some of which were small, and some of which were many megapixels in size. Fortunately most of the leg work for this project was already done thanks to this post on the PathtoSharePoint.com blog.

As the post on Path to SharePoint demonstrates, these web-optimized images can be accessed by going to the following URL:

http://[path to list]/_w/[image filename without extension]_[extension].jpg

For example, if our image file is “Image001.JPG”, the web-optimized image will be located here:

http://server/volunteer_images/_w/image0001_jpg.jpg

Note: Use “_w” for web-optimized images (usually 640px wide) and “_t” for thumbnail images (usually 160px wide).

To load the optimized images into a Data View Web Part, use the following HTML and XSLT:

<img src="/{@FileDirRef}/_w/{concat(substring-before(translate(@FileLeafRef,'QWERTYUIOPASDFGHJKLZXCVBNM','qwertyuiopasdfghjklzxcvbnm'),concat('.',@FileType)),'_',@FileType,'.jpg')}" alt="{@Description}" />

Decoding the HTML and XSLT

The code starts with a basic image tag:

<img src="" alt="" />

From this point it’s a matter of adding information to the src and alt attributes.

The first part of the src attribute starts with a relative URL from the main site collection (the forward slash), then includes a reference to the Picture Library’s location (the “{@FileDirRef}” part), and finally adds the web-optimized sub-directory from the library (“/_w/”).

<img src="/{@FileDirRef}/_w/" />

The next part of the src attribute is a lot more complex:

{concat(substring-before(translate(@FileLeafRef,'QWERTYUIOPASDFGHJKLZXCVBNM','qwertyuiopasdfghjklzxcvbnm'),concat('.',@FileType)),'_',@FileType,'.jpg')}

The end-result we need after the sub-directory (using our example from above) is “image001_jpg.jpg.” However, getting to this point is not easy as you can see from the highlighted code above. First, we need to take the file name and translate it so all letters are lowercase (just in case an image is uploaded with an uppercase file extension). To do this we use the translate function:

translate(@FileLeafRef,'QWERTYUIOPASDFGHJKLZXCVBNM','qwertyuiopasdfghjklzxcvbnm')

The resulting file name goes from “Image001.JPG” to “image001.jpg.”

Next we need to split our file name so we only have the part before the file extension (e.g. “image001”). To do this we use the substring-before function and wrap it around the translate function:

substring-before(translate(@FileLeafRef,'QWERTYUIOPASDFGHJKLZXCVBNM','qwertyuiopasdfghjklzxcvbnm'),".jpg")

The resulting file name goes from “Image001.JPG” to “image001.jpg.”

Next we need to split our file name so we only have the part before the file extension (e.g. “image001”). To do this we use the substring-before function and wrap it around the translate function:

substring-before(translate(@FileLeafRef,'QWERTYUIOPASDFGHJKLZXCVBNM ','qwertyuiopasdfghjklzxcvbnm_'),".jpg")

This splits the file name before the “.jpg” part, resulting in “image001” instead of “image001.jpg.” However, we want to account for all image types, not just JPEGs. So, we replace the “.jpg” part of the formula with a concatenation of a period and the @FileType field, which lists the file type in lowercase. Our final substring-before formula looks like this:

substring-before(translate(@FileLeafRef,'QWERTYUIOPASDFGHJKLZXCVBNM ','qwertyuiopasdfghjklzxcvbnm_'),concat('.',@FileType))

Now the file name should be all lowercase, have no spaces, and have no file extension regardless of whether it’s a JPEG, GIF, PNG, etc. Next we need to combine that with an underscore, the file extension (minus the period), and the file extension with the period. To do this we use another concatenation formula.

First, we include the substring-before formula:

concat(substring-before(translate(@FileLeafRef,'QWERTYUIOPASDFGHJKLZXCVBNM','qwertyuiopasdfghjklzxcvbnm'),concat('.',@FileType)),

Then we add the underscore and the file extension without the period:

concat(substring-before(translate(@FileLeafRef,'QWERTYUIOPASDFGHJKLZXCVBNM','qwertyuiopasdfghjklzxcvbnm'),concat('.',@FileType)),'_',@FileType,

Finally, we add a period and the jpg file extension (all web-optimized images are converted to JPEG format):

concat(substring-before(translate(@FileLeafRef,'QWERTYUIOPASDFGHJKLZXCVBNM','qwertyuiopasdfghjklzxcvbnm'),concat('.',@FileType)),'_',@FileType,'.jpg')

It’s always a good practice for accessibility to include the alt attribute, so you can use the @Description field to display text if the image does not load or a user has a screen reader:

<img src="/{@FileDirRef}/_w/{concat(substring-before(translate(@FileLeafRef,'QWERTYUIOPASDFGHJKLZXCVBNM','qwertyuiopasdfghjklzxcvbnm'),concat('.',@FileType)),'_',@FileType,'.jpg')}" alt="{@Description}" />

Now our Xpath is complete and our web-optimized images will load.

Putting It All Together

I modified the unordered list layout in my Data View Web Part to work with the Anything Slider jQuery plugin. Each list item includes the Xpath above as part of the XSL template. I also included a reference to the Description column from the Picture library so each image would also display a caption if the Description column was populated.  Finally, by changing the CSS for the AnythingSlider I was able to come up with a custom branded image slideshow web part to put onto the stakeholder’s SharePoint site.

Here is the full XSL:

<Xsl>

	<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal">
		<xsl:output method="html" indent="no"/>
		<xsl:decimal-format NaN=""/>
		<xsl:param name="dvt_apos">&apos;</xsl:param>
		<xsl:variable name="dvt_1_automode">0</xsl:variable>

		<xsl:template match="/" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:SharePoint="Microsoft.SharePoint.WebControls">
			<xsl:call-template name="dvt_1"/>
		</xsl:template>

		<xsl:template name="dvt_1">
			<xsl:variable name="dvt_StyleName">BulTitl</xsl:variable>
			<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />
			<div class="anythingSlider">
				<div class="wrapper">
					<ul>
						<xsl:call-template name="dvt_1.body">
							<xsl:with-param name="Rows" select="$Rows" />
						</xsl:call-template>
					</ul>
				</div><!--End wrapper-->
			</div><!--End anythingSlider-->
		</xsl:template>

		<xsl:template name="dvt_1.body">
			<xsl:param name="Rows" />
			<xsl:for-each select="$Rows">
				<xsl:call-template name="dvt_1.rowview" />
			</xsl:for-each>
		</xsl:template>

		<xsl:template name="dvt_1.rowview">
			<li>
				<div class="textSlide">
					<img class="photo" src="/{@FileDirRef}/_w/{concat(substring-before(@FileLeafRef,concat('.',@FileType)),'_',@FileType,'.jpg')}" alt="Caption" />
					<div class="imageCaption">
						<h3><xsl:value-of select="@Caption" /></h3>
						<p><xsl:value-of select="@Description" /></p>
					</div>
					<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
						<br /><span ddwrt:amkeyfield="ID" ddwrt:amkeyvalue="ddwrt:EscapeDelims(string(@ID))" ddwrt:ammode="view" />
					</xsl:if>
				</div>
			</li>
		</xsl:template>

	</xsl:stylesheet>
</Xsl>

Here is the stylesheet I used:

/*
    anythingSlider v1.0

    By Chris Coyier: http://css-tricks.com
    with major improvements by Doug Neiner: http://pixelgraphics.us/
    based on work by Remy Sharp: http://jqueryfordesigners.com/
*/

/*SLIDER RESETS*/
.anythingSlider {
	color: #ffffff;
	background-color: #292929;
	font-family: verdana, sans-serif;
	font-size: 13px;
	}

/*SLIDER LAYOUT*/

.anythingSlider {
	position: relative;
	display: block;
	float: left;
	width: 620px;
	}
.anythingSlider .wrapper {
	position: relative;
	width: 620px;
	overflow: auto;
	height: 413px;
	}
.anythingSlider .wrapper ul {
	list-style-type: none;
	margin: 0;
	padding: 0;
	width: 9999999px;
	}
.anythingSlider ul li {
	display: block;
	float: left;
	padding: 0;
	margin: 0;
	width: 620px;
	height: 413px;
	overflow: hidden;
	}
.textSlide {
	position: relative;
	width: 620px;
	height: 413px;
	text-align: center;
	}
.textSlide img {
	display: block;
	margin: 0 auto;
	}
.textSlide .imageCaption {
	position: absolute;
	text-align: left;
	color: #000000;
	top: 313px;
	left: 0px;
	background-color: #ffffff;
	opacity:.7;
	filter:alpha(opacity=70);
	height: 100px;
	width: 100%;
	}
.imageCaption h3, .imageCaption p {
	padding: 5px;
	margin: 0;
	}
.arrow {
	display: block;
	width: 24px;
	height: 24px;
	line-height: 22px;
	cursor: pointer;
	text-decoration: none;
	text-align: center;
	font-weight: bold;
	font-size: 15px;
	color: #777777 !important;
	position: absolute;
	top: 420px;
	z-index: 999;
	}
.arrow:hover {
	background-color: #999999;
	}
.forward {
	float: right;
	right: 0;
	}
.back {
	float: left;
	}
#thumbNav {
	clear: both;
	width: 620px;
	}
#thumbNav #holder {
	display: inline;
	float: left;
	margin-left: 22px;
	}
#thumbNav #holder a {
	display: inline;
	float: left;
	width: 24px;
	height: 24px;
	padding: 0;
	margin: 7px 12px;
	background-color: #777777;
	}
#thumbNav #holder a:hover {
	background-color: #eeeeee;
	}
#thumbNav #holder a.cur {
	background-color: #ffffff;
	}
.slideThumb {
	display: block;
	width: 20px;
	height: 20px;
	border: none;
	margin: 2px;
	}
#start-stop {
	display: block;
	clear: both;
	background: #333333;
	color: white;
	padding: 0;
	margin-left: 580px;
	margin-top: 7px;
	line-height: 20px;
	width: 40px;
	font-size: 9px;
	text-align: center;
	text-decoration: none;
	}
#start-stop:hover {
	background-color: #555555;
	}

/*PREVENT SLIDE CONTENT FROM INHERITING SLIDER LAYOUT STYLES*/
.anythingSlider .wrapper ul ul {
	position: static;
	margin: 0;
	background: none;
	overflow: visible;
	width: auto;
	border: 0;
	list-style-type: disc;
	display: list-item;
	}
.anythingSlider .wrapper ul ul li {
	float: none;
	height: auto;
	width: auto;
	background: none;
	}

/*SLIDE CONTENT STYLES*/

.textSlide h3 {
	font-size: 16px;
	font-family: arial, sans-serif;
	margin: 0;
	padding: 5px 10px;
	}
.textSlide p {
	margin: 0;
	padding: 5px 10px;
	}

And finally, here is an example of the resulting image slideshow:

Sample AnythingSlider slide show DVWP
A sample of the resulting slide show using a DVWP, jQuery, and the AnythingSlider.

When I get some more time I hope to clean up the CSS a bit and take into account image files that have spaces in their names (right now they won’t load due to the Xpath not converting spaces into underscores). I’m open to any suggestions!


Comments

  1. Thanks for the article. its really great to see. Unfortunately the above code didn't work for me. below are the steps i followed 1. Created picture library and added images 2. In SPD created a blank aspx page 3. Insert Dataview webpart with mulitple view 4. Then replace with your code and added styles in style sheet 5. I already have jquery-1.4.3.min.js & jquery.anything.slider.js refernce in master page. But while running I can see a black box with scrollbar and images arranged without any animation. Could you please help me to fix this issue? Thanks in advance -Jim
    1. Hi Jim. It sounds like jQuery or the AnythingSlider plugin aren't being loaded properly. Make sure that jQuery is loaded before the AnythingSLider plugin. I used an older version of the Anything Slider plugin, so if you grabbed a newer version you might need to use some different class names and/or id's in the HTML that your data view web part generates. Also check your Anything Slider initialization script and see if the problem is with that. The Anything Slider plugin site should have more documentation on getting it working.
  2. Josh, looking to do the same but with XML/XSLT web part. Was this SP 2k7? What javascript did you use to instantiate the slider? Did you implement the colorbox functionality? What versions of jQuery, AnythingSlider, etc. did you use? Great stuff. Thx! Joe
    1. It was jQuery 1.3.2, AnythingSlider 1.2 in MOSS 2007. This is the code I used to initialize the slider:
      function formatText(index, panel) {
      	  return index + "";
      	}
      
      	$(function () {
      
      		$('.anythingSlider').anythingSlider({
      			easing: "swing",        // Anything other than "linear" or "swing" requires the easing plugin
      			autoPlay: true,                 // This turns off the entire FUNCTIONALY, not just if it starts running or not.
      			delay: 5000,                    // How long between slide transitions in AutoPlay mode
      			startStopped: false,            // If autoPlay is on, this can force it to start stopped
      			animationTime: 1200,             // How long the slide transition takes
      			hashTags: false,                 // Should links change the hashtag in the URL?
      			buildNavigation: true,          // If true, builds and list of anchor links to link to each slide
      			pauseOnHover: false,             // If true, and autoPlay is enabled, the show will pause on hover
      			startText: "Play",             // Start text
      			stopText: "Pause",               // Stop text
      			navigationFormatter: formatText,       // Details at the top of the file on this use (advanced use)
      			defaultThumb: ''    //set the default thumbnail if no other are found
      		});
      		
      		$("#slide-jump").click(function(){
      			$('.anythingSlider').anythingSlider(6);
      		});
      		
      	});
  3. How do i use this if i just want to display static pictures along with the title associated with the picture (preferably thumb nail sizes) without any jquery . Would this work in that case
    1. You can use this, but thumbnails are in the "_t" directory instead of the "_w" directory in the Picture library. Modify your XSL to output just the image and the title, and modify your CSS to make things look the way you want. There's no need for jQuery if you are just displaying the images on the page.

Comments are closed