|
Comments
|
Today's Top SOA Links
Silverlight News Desk PDF for Silverlight
Leveraging the power of Silverlight to view PDF documents and forms (Updated for Silverlight 3 and 4)
By: Amyuni Tech
Jan. 6, 2011 09:37 AM
Using Microsoft Silverlight, developers can provide their users with content-rich web applications that are not limited to text and images, and which can now include complex graphics and better interaction with users. A useful add-on to Silverlight would be the ability to display high quality PDF documents that would be easily readable by the users as compared to displaying documents as Jpeg images. Now that PDF has become the standard format for document storage and forms processing in most corporations, we thought that Silverlight applications would benefit from the ability to natively serve PDF documents and forms. In this paper, we will show how to use the Amyuni PDF components to dynamically view PDF documents within a Silverlight control. We will discuss how to create a Silverlight 3 control to display and interact with PDF documents. The same control can be used for viewing PDF, XPS or any type of document rather than just images. The documents would be located on the server and viewed by the client within a Silverlight object without having to download any files to the client. The framework that is presented can be easily expanded to add interactivity when the PDF files contain annotations or form fields. Requirements (Server Side) Requirements (Client Side) Implementation
The basic requirements for building a document viewer using Silverlight are:
Using the WebClient Object and the Application.GetResourceStream() method Within the ZIP package, each page description can is stored as a separate XAML file and all resources used by that page stored in a virtual folder. Downloading the ZIP package and extracting objects from it can be asynchronous and the ZIP package dynamically created on the server and streamed back to the client without resorting to temporary files, is exactly what we needed. The basic syntax for using the WebClient object is as follows: public void LoadFromUrl(string url) { // Retrieves the XAML of document packaged in a ZIP format located at the specified URL // which can be something like: // "http://www.amyuni.ca/PageTurnPdf/pdf.asp?PDFFile=doc.pdf" or // "http://www.amyuni.ca/PageTurnPdf/myXAMLpackage.zip" ... // start web download using the WebClient object Uri uri = new Uri( url ); WebClient webClient = new WebClient(); webClient.AllowReadStreamBuffering = true; //speeds application response time // add event listener to detect when data is available webClient.OpenReadCompleted += new // add event handler for catching download progress notifications webClient.DownloadProgressChanged += new // start request webClient.OpenReadAsync(uri, webClient); } private void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { // Start loading the document // e.Result will contain the XAML ZIP Stream m_zipStream = e.Result; ... // get XAML of document Stream stream = GetPartFromZipPackage("Document/document_1.fdoc", m_zipStream); StreamReader sreader = new StreamReader(stream); string sDoc = sreader.ReadToEnd(); ... // get XAML of page from the ZIP package Stream stream = GetPartFromZipPackage("Pages/page_" + (pageNumber + 1).ToString() + // convert to string StreamReader sreader = new StreamReader(stream); string sPageXaml = sreader.ReadToEnd(); ...
Extracting and Rendering Images private void ProcessElements(object _elems) { // process all page elements to set: // - the source of all image elements // - the font of all text elements // for ( int i = 0; i < elems.Count; i++ ) { UIElement elem = elems[i]; //a child UIElment Image img = elem as Image; ... // the Source would be a string if (img.Source != null && img.Source.ToString() != "") { var src = img.Source; if (src != null) { string s = src.ToString(); // set the source after removing the leading slash Stream stream = GetPartFromZipPackage(s.Substring(1), BitmapImage bitmap = new BitmapImage(); bitmap.SetSource(stream); img.Source = bitmap; } } ... // loop recursively through all children of the current element ProcessElements(elem.children); ... } }
' Optimize the document to line level in order to improve the XAML export objPdf.OptimizeDocument 1
When the font used in the source document is not available on the client PC, Silverlight would substitute with a different font which usually gives results that are not satisfactory. Silverlight provides a mechanism for specifying the font used to display a specific element, as long as the font is in OpenType or TrueType format. The Downloader object can be used in this case to package all the fonts used by the document. The fonts are embedded in the ZIP package as partially embedded fonts that are not usable by the end-user in order to avoid font licensing issues. In parallel to the image processing described above, the sample viewer loops through all text objects and sets the font source for each object to be one of the fonts in the ZIP package: // set the font source for all text elements to fonts retrieved from the ZIP package if ( elem.GetType() == typeof(TextBlock) ) { TextBlock tb = (TextBlock) elem; // set the FontSource tb.FontSource = new FontSource( m_zipStream ); ...
The text element’s “FontFamily” attribute maps the text’s font to one of the fonts packaged in the ZIP file. This is done automatically by the Silverlight component when the requested font is not located on the end-user’s system. <% ' Set the returned content type to be a ZIP package Response.ContentType = “application/x-zip-compressed” ' Get the PDF filename requested by the user strFilePath = Request.QueryString( “PDFFile” ) ' Get the pages subset(s) string requested by the user if specified ' eg.: "1,3,10-25,4,125-100" strPages = Request.QueryString( "Pages" ) ' Create the PDF Creator ActiveX object and open the document ' This will throw an exception if the control is not installed ' or the document not found Set objPdf = Server.CreateObject(“PDFCreactiveX.PDFCreactiveX”) ' Use OpenEx to use deferred document loading (does not load entire document) objPdf.OpenEx Server.MapPath( strFilePath ), ““ ' Set the Document attribute PageSequenceStr. If empty string, all pages will be included objPdf.ObjectAttributeStr "Document", "PageSequenceStr", strPages ' Optimize the document to line level in order to improve the XAML export objPdf.OptimizeDocument 1 ' return the XAML attribute of the document object which is a ZIP package Response.BinaryWrite objPdf.ObjectAttribute( “Document”, “XAML” ) Set objPdf = Nothing %> Expanding the Sample to View Documents other than PDF To render other types of documents, they should be first converted into PDF using the Amyuni PDF Converter, then streamed back to the client as a ZIP package. The PDF Converter product is available for download from: http://www.amyuni.com/en/developer/pdfconverter. A sample for converting documents into PDF on a server can be found at: http://www.amyuni.com/en/resources/technicalnotes/
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week |
|||||||||||||||||||||||||||