Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Making a Multipage Embedded Viewer in HTML5 and jQuery

28 Jan 2016 1  
In this CodeProject lab we are going to build an UI control to display multiple pages in a single container.

This article is in the Product Showcase section for our sponsors at CodeProject. These articles are intended to provide you with information on products and services that we consider useful and of value to developers.

Making the Viewer

HTML5 currently does not have a way to display multipage documents embedded in a web application. In this CodeProject lab we are going to build an UI control to display multiple pages in a single container. When creating a reusable component in Visual Studio I prefer to start with a blank web application.

Select File > New Project > Web > Blank Web Application

To begin creating the viewer object I like to think about how I want to use it and the simplest way to set up a viewer dynamically for the user is something like this:

var viewer = CreateViewer("#myViewerDiv");
viewer.OpenFile("default");

We use a factory method to instantiate the viewer and a simple viewer API method to open the images. All right, easy enough, so now we can create the js library file.

Select the project in the solution explorer and add a new Javascript file to the project. Once this is created we can make the CreateViewer function’s skeleton

function CreateViewer(target){
 var viewerobj = {
  ui:$(target),
  OpenFile: function(path) {}
 };
 viewerobj.ui.addClass("ViewerUI");
}

With function we have now marked a div as the viewer and applied a style class to it so we can appropriately style it. For starters I recommend this stylesheet:

.ViewerUI

{

    width:98vw;

    height:600px;

    border: 1px solid black;

    background-color: lightgray;

    overflow-y:auto;

    overflow-x:scroll;

}

We can now run the application to see the application of the styles

Good! We are making progress. Now we need to load the images into the div from the server. To accomplish this we will need to make some sort of serverside functionality to gather and return the images. For this I am going to use a asp.net generic handler object.

Select your project in the solution explorer and add a new Generic Handler object

public void ProcessRequest(HttpContext context)
{
 string directorypath = context.Server.MapPath("/Images/");
 string target = context.Request.QueryString["target"];
 context.Response.Write(GetFolder(directorypath,target));
}

Then we need to create the GetFolder function which will return the relevant data to the clientside of the images in a specific folder on the server. The relevant data for each image for the purposes of the clientside are:

  • ImageURL (to be able to open the image)
  • ImageSize (to be able to scale the img tag)

I prefer complexities of data to be handled on the serverside, so in the function below I am creating a JSON string for the server's return data while getting all of the images in the folder.

public string GetFolder(string basedir, string target)
{
 string[] images = Directory.GetFiles(basedir+"\\"+target);
 StringBuilder sb = new StringBuilder();
 sb.Append("{images:[");
 int emptysize = sb.Length;
 foreach (string path in images)
 {
   string filename = Path.GetFileName(path);
   sb.Append("{");
   sb.Append(CreateImageObject(new Bitmap(path),"\\\\Images\\\\"+target+"\\\\"+filename));
   sb.Append("}");
   sb.Append(",");
 }
 if(sb.Length!=emptysize)
  sb.Remove(sb.Length-1, 1);
 sb.Append("]}");
 return sb.ToString();
}

I apologize for the verbosity of the code above, but I felt it was important for the purpose of this exersise to not use any short cuts to create a JSON string that could be consumed on the client side for this purpose. So the last function needed on the client side is CreateImageObject, that simply formats the required data for each image in the folder to be displayed in the viewer.

private string CreateImageObject(Bitmap bitmap, string filename)
{
   StringBuilder sb = new StringBuilder();
   sb.Append("width:");
   sb.Append(bitmap.Width);
   sb.Append(",");
   sb.Append("height:");
   sb.Append(bitmap.Height);
   sb.Append(",");
   sb.Append("filename:");
   sb.Append("\"");
   sb.Append(filename);
   sb.Append("\"");
   return sb.ToString();
}

With that function in place the serverside is complete. We now have a function that will take a folder name and return a JSON string describing the images contained in the folder. All that is left is to have the client call for the information and add the images to the DOM. To do this we go back to the clientside js file:

OpenFile: function(path) {
        var send = { Open: "folder", target: imageTarget }
        ui.children().remove();
        $.get("ViewerHandler.ashx", send, imageDataRecieved);
}

The function is three simple steps. Make a data object to send to the server, clear the viewer, then send the request with a callback function. The callback function then will be used to consume the returned data object finally creating the viewer. The most important function of this viewer is to provide properly sized images dynamically based on the space the viewer has to work with.

function imageDataRecieved(data,status,jqXHR)
{
    var images = eval(data);
    var viewerWidth = _vobj.ui.width()-10-20; // padding scrollbar
    images.forEach(function (image) {
        var ratio = viewerWidth / image.width;
        var img = jQuery("<img></img>");
        img.attr("src", image.filename);
        img.css("width", viewerWidth);
        img.css("height", image.height * ratio);
        img.css("border", "1px solid black");
        img.css("margin-left", "5px");
        img.css("margin-bottom", "5px");
        _vobj.ui.append(img); //this is an internal pointer to the viewer object
    });
}

This final function takes the JSON string, converts it into usable data and then puts each image into the viewer after sizing it to fit properly while maintaining each images aspect ratio. With the last function in place running the page yields our first functional viewer.

Extending the viewer

Extending a viewer has the most to do with what needs to be done with it. One of the main reasons to have a html viewer is to add support for image formats that browsers do not support natively. The most common formats for scanned documents are PDF and TIFF. To add support for those formats the server would have to be able to open those files and create temporary single page web native image files for each page contained within.

Atalasoft provides PDF and TIFF decoders and a pre-built viewer to display those file formats. Visit www.atalasoft.com/webdocumentviewer to learn more.

If there is anything else that you would need a viewer to do, please post in the comments and I may be able to follow up and create more extensions for this basic viewer in later posts.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here