Load SharePoint Web-optimized Images into a DVWP
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">'</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:

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
Comments are closed