INTRODUCTION
To View a demo first, use the link to YouTube video at the bottom of the post.
QR Codes is a square image made up of two colours; normally
white as a background colour and black as the foreground colour. The image
represents a bitmap and can contain simple text limited to a short paragraph;
but it is more useful when it represents a url, or a business card etc. In
these cases, a QR Code Reader can read the encoded url and or business card and
launch the site or make a call, import the contact and so on, depending on your
QR code reading software. Most phones and Pads have QR Code scanners.
USAGE
I’ve developed the solution for an Agricultural University. They conduct a lot of experiments, in the field and labs and require a simple label against each plot or pot or whatever else it is. The aim is to carry a mobile devices with you, scan the QR Code, this would automatically direct to the related SharePoint page/list-item where you can find out more information or update findings and so on. The solution shown simply concentrates on the integration with SharePoint and is a nice complement to my Short Url stuff.
SOLUTION(S)
The solution is a SharePoint feature that extends a document
library allowing it to store a QR Code against the document. Here the technical
challenge isn’t the ability to generate the code (open-source library is used
for that), but rather how we can show these consistently across all pages,
through embedding them within the pages. The QR Code generation library used is
GMA.QrCodeNet.Encoding (http://qrcodenet.codeplex.com/) . I have used an
earlier version, but it has a more current version available of CodePlex.
Technical Details
The solution is developed using Visual Studio 2010. It uses the SharePoint extensions known as the CKSDev tool kit. These need to be installed inside Visual Studio. This solution will also work with SharePoint 2010 Standard/Enterprise or SharePoint Foundation 2010. The following diagram shows the solution within solution explorer.
In the solution the following are the key elements;
- Feature folder – This contains the details of the feature such as Title, Description, feature activation scope etc. The scope of QR codes is defined at the web level.
- Event Receiver – This contains the c# code to run event when a document is added or updated. It contains the code to generate the QR code, add it to a special images library and store it.
- Images Library – Stores the actual images.
- Custom field – A field of type image that can be added to any images library. This stores the url for the image and displays the associated image in display mode.
Activation
The QR code feature can be activated for any SharePoint site. This is done through ‘Manage site features’ – a link for this can be found on the ‘Site Settings’ page. The solution is deployed globally and is available in all site collections. The feature, available for each individual web, on activation, creates an images list on that web. QR codes can be generated for any documents library, and includes all libraries based on document library type such as site pages library, publishing pages library etc.
Once the feature is activated, the document library will not automatically start creating QR codes; instead the QRImages column needs to be manually added to a documents library. This can be done through ‘Document Library Settings’ page. Simply select ‘add column from existing’ and then add the QR Image column.
There is no visible command or buttons to generate QR codes; instead once a document library is setup as above, any modifications to a document metadata or the update of the document as well as upload of new document will start the process of generating a new QR code. You must manually refresh the list view page (if QR code is one of the visible column) to see the new image.
Feature Details
The following are a number of Elements files for various aspects of the feature;
<Feature xmlns="http://schemas.microsoft.com/sharepoint/" Description="Generates QR Code for document libraries that have QRImage field added to them" Id="694ffa27-3094-4a63-8183-200cf35e0fd6" Scope="Web" Title="Harper-Adams QR Codes Generation"> <ElementManifests> <ElementManifest Location="QRImage\Elements.xml" /> <ElementManifest Location="EventReceiverGenerateQR\Elements.xml" /> <ElementManifest Location="QRCodeImages\Elements.xml" /> </ElementManifests> </Feature>
The QRImage Field
This field needs to be added to any document library that requires QR Code.
<Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Field Type="URL" DisplayName="QRImage" Required="FALSE" EnforceUniqueValues="FALSE" ShowInEditForm="FALSE" ShowInNewForm="FALSE" ShowInViewForms="TRUE" Indexed="FALSE" Format="Image" Group="Harper Adams Columns" ID="{f74bc8b8-6370-48bc-9ed2-d869b2a2ad0f}" SourceID="{5c96e6a5-6239-4920-b496-592a4d541b15}" StaticName="QRImage" Name="QRImage" > </Field> </Elements>
The Images Library Instance
The following Images Library is created on feature activation
<Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <ListInstance Title="QR Code Images" OnQuickLaunch="TRUE" TemplateType="109" FeatureId="00bfea71-52d4-45b3-b544-b1c71b620109" Url="Lists/QRCodeImages" Description="This holds the QR code images"> </ListInstance> </Elements>
The Event Receiver
When an item is added or updated, one of these is run.
<Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <!-- Note Pages Library is 850, but as the base type is Document Library - it should also fire for that as well --> <Receivers ListTemplateId="101"> <Receiver> <Name>EventReceiverGenerateQRItemAdded</Name> <Type>ItemAdded</Type> <Assembly>$SharePoint.Project.AssemblyFullNamelt;/Assembly>
<Class>QRCodeLibraryEnhancements.EventReceiverGenerateQR.EventReceiverGenerateQR</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
<Receiver>
<Name>EventReceiverGenerateQRItemUpdated</Name>
<Type>ItemUpdated</Type>
<Assembly>$SharePoint.Project.AssemblyFullName
lt;/Assembly>
<Class>QRCodeLibraryEnhancements.EventReceiverGenerateQR.EventReceiverGenerateQR</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
<Receiver>
<Name>EventReceiverGenerateQRItemDeleted</Name>
<Type>ItemDeleted</Type>
<Assembly>$SharePoint.Project.AssemblyFullName
lt;/Assembly>
<Class>QRCodeLibraryEnhancements.EventReceiverGenerateQR.EventReceiverGenerateQR</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
</Receivers>
</Elements>
The Code
Most of the code sits within the Event Receivers. The following are the only items of interest.
private string CreateAndSaveQRCode(Guid siteGuid, Guid webGuid, string url, string name) { QrEncoder qrEncoder = new QrEncoder(ErrorCorrectionLevel.H); QrCode qrCode = new QrCode(); qrEncoder.TryEncode(url, out qrCode); Renderer renderer = new Renderer(5, Brushes.Black, Brushes.White); MemoryStream ms = new MemoryStream(); renderer.WriteToStream(qrCode.Matrix, ms,System.Drawing.Imaging.ImageFormat.Jpeg); string weburl = string.Empty; SPSecurity.RunWithElevatedPrivileges(delegate() { using (SPSite site = new SPSite(siteGuid)) using (SPWeb web = site.OpenWeb(webGuid)) { SPPictureLibrary pic = (SPPictureLibrary)web.Lists["QR Code Images"];//Images is the picture library name SPFileCollection filecol = pic.RootFolder.Files;//getting all the files which is in pictire library filecol.Add(name + ".jpg", ms, true);//uploading the files to picturte library weburl = web.Url; } }); return weburl + "/Lists/QRCodeImages/" + name + ".jpg"; }
Within the event receiver code, it is easy enough to get various Ids. Nonetheless I’ve added the important part below. Note that you must disable Event Firing when updating the same listitem to avoid an infinite loop.
SPListItem item = properties.ListItem; if (!item.Fields.ContainsField(IMAGE_FIELD)) return; string url = CreateAndSaveQRCode(properties.SiteId, properties.Web.ID, (string)item["EncodedAbsUrl"], item.UniqueId.ToString()); SPFieldUrl urlField = item.Fields.GetFieldByInternalName(IMAGE_FIELD) as SPFieldUrl; if (item[urlField.Title] != null) { SPFieldUrlValue urlFieldValue = urlField.GetFieldValue(item[urlField.Title].ToString()) as SPFieldUrlValue; urlFieldValue.Url = url; urlFieldValue.Description = "QR code image"; } else { SPFieldUrlValue value = new SPFieldUrlValue(); value.Description = "QR code image"; value.Url = url; item[IMAGE_FIELD] = value; } base.EventFiringEnabled = false; item.SystemUpdate(); base.EventFiringEnabled = true;
Demo
The following short video (sorry, no sound) demos both Tiny Url and QR Codes. It has no editing etc. done to it, but otherwise it is pretty Okay.