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

HTML5 Zero Footprint Viewer for DICOM and PACS – Part 2

7 Jan 2013 1  
In this article, we will continue digging into the HTML5 DICOM viewer and take a closer look at its client side annotations and markup.

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.

Introduction

There are many important aspects of a complete Zero Footprint DICOM Viewer built using HTML5 and JavaScript.  The latest medical imaging development product from LEADTOOLS has it all: image display, image processing, fast client-side window leveling, series stack, annotations and more.  In our first article, we introduced the viewer and highlighted its PACS query / retrieve and client-side window leveling features.  In this article, we will continue digging into the HTML5 DICOM viewer and take a closer look at its client side annotations and markup.

Key HTML5 DICOM Viewer Features in LEADTOOLS SDKs

  • HTML5 / JavaScript Viewer Control for cross-platform image viewing
  • Supports both mouse and multi-touch (gesture) input
  • Fast, client-side tools for Window Level, Series Stack, image processing and more
  • View DICOM images anywhere, on your desktop, tablet or mobile device, from your local archive or a remote PACS using DICOM communication
  • RESTful Web Services for performing query/retrieve and streaming DICOM metadata and image data in any format or compression
  • Native HTML5 Image Annotation and Markup
  • Signed and unsigned display for extended grayscale images
  • Client caching of downloaded image data for fast reloads and network traffic reduction
  • Full featured HTML5 DICOM Viewing application with source code, for easy customization and branding

SDK Products that Include HTML5 DICOM Viewer Technology

The HTML5 DICOM Viewer Code

The LEADTOOLS HTML5 zero footprint DICOM viewer is actually a fully functional ASP.NET web application that integrates directly with any PACS to stream DICOM images to the client.  The source code is provided so that developers can easily make modifications, customizations and branding changes to the application as they see fit.  In what follows below, some of the key features are explained with screenshots and code snippets to illustrate the benefits of the toolkit.

HTML5 Annotations for DICOM Images

Once a DICOM series has been selected and the images begin streaming to the viewer, the annotations are initialized for use.  The AnnAutomationManager object is created and attached to the viewer.  As you can see below, the annotations are given their own HTML5 canvas which is overlaid on top of the viewer.  This allows the annotations to be drawn in a separate layer from the image and increases efficiency and reduces the possibility for corruption of the canvas being displayed underneath.  

function initializeAnnotations() {
   _automationManager = new Leadtools.Annotations.Automation.AnnAutomationManager();

   _automationManager.createDefaultObjects();
  
   _automationManager.findObjectById(Leadtools.Annotations.Core.AnnObject.rulerObjectId).get_objectTemplate().set_measurementUnit(6);
   _automationManager.findObjectById(Leadtools.Annotations.Core.AnnObject.polyRulerObjectId).get_objectTemplate().set_measurementUnit(6);
   _automationManager.findObjectById(Leadtools.Annotations.Core.AnnObject.protractorObjectId).get_objectTemplate().set_measurementUnit(6);
   
   var divElemnt = document.getElementById("ViewerParent");
   _overlayCanvas = document.createElement("canvas");

   _overlayCanvas.id = "overlayCanvas";

   _overlayCanvas.width = $(divElemnt).width();
   _overlayCanvas.height = $(divElemnt).height();

   var parent = document.getElementById(_leadViewer.get_canvasId()).parentNode;

   parent.appendChild(_overlayCanvas);

   _automationInteractiveMode = new Leadtools.Annotations.Automation.ImageViewerAutomationControl(_leadViewer);
}

The great thing about the AnnAutomationManager is that it does everything for you.  All the events are handled internally so mouse and touch events are correctly interpreted to draw, modify, transform and scale the annotations anytime the user interacts with the canvas or annotation objects.  Additionally, it will rescale and translate the annotations accordingly whenever the viewer’s display properties such as zooming and scrolling are altered so that the annotations stay in the same logical position on the image.

To use the annotations, all one must do next is select the object you wish to draw, or use the Select tool to modify an existing annotation.  In the demo application, we include several buttons that, when clicked, enable the desired annotation tool.  You can enable or disable as many as you wish, but we ship the demo with the most popular annotations used in the healthcare industry (Arrow, Rectangle, Ellipse, Text, Highlight, Ruler, Poly Ruler and Protractor).  The snippet below shows the onClick event of several buttons to give an idea of how little is needed for so many features.

function OnAnnotationSelect() {
   if (null != _leadViewer && null != _currentAutomation && _annotationSelect.enabled) {
      AutomationService();
      _currentAutomation.get_manager().set_currentObjectId(Leadtools.Annotations.Core.AnnObject.selectObjectId);
   }
}
function OnAnnotationArrow() {
   if (null != _leadViewer && null != _currentAutomation && _annotationArrow.enabled) {
      AutomationService();
      _currentAutomation.get_manager().set_currentObjectId(Leadtools.Annotations.Core.AnnObject.pointerObjectId);
   }
}

function OnAnnotationText() {
   if (null != _leadViewer && null != _currentAutomation && _annotationText.enabled) {
      AutomationService();
      _currentAutomation.get_manager().set_currentObjectId(Leadtools.Annotations.Core.AnnObject.textObjectId);
   }
}

Loading and Saving Annotations Using the Web Service

The ability to load and save annotations is crucial to the workflow of medical applications.  First and foremost, they help describe, point out, or make note of something in the image.  The most important piece of information is still the image itself so annotations should have a simple method of being hidden and brought back.  DICOM viewing applications are also collaborative.  Radiologists, nurses, doctors and patients alike can look at the images and often need to get second opinions, making the ability to pass notes and annotations back and forth very handy.  Finally, this is a web application so the users of the application will need to see the image and annotations on any computer, mobile device or tablet from any location.

LEADTOOLS uses a RESTful web service to load and save the annotations.  As shown below, the first step is to get a description (e.g. "Dr. Brown’s Notes", "John please review!", etc.) and the image frame on which the annotations are drawn (SOP Instance UID).  These two pieces of information are sent in the userData parameter via JSON, and the LEADTOOLS web service takes care of the rest by saving the annotation data to the server’s database.

function DoSaveAnn(annotationsData) {
   var firstFrame = _dicomLoader.GetFrame(0);
   var description = $('#annSaveDescText').val();

   if (!description) {
      alert("You must enter a description");
      return;
   }
   
   var series = firstFrame.Instance.SeriesInstanceUID;
   var userData = { Description: description,
      ReferencedSOPInstance: firstFrame.Instance.SOPInstanceUID
   };

   annotationsProxy.SaveAnnotations(series, annotationsData, JSON.stringify(userData), SaveAnnotationsError, SaveAnnotationsSuccess);
}

When an image frame is loaded, the application does a quick permissions check and then retrieves an array of previously saved annotation files associated with the image.

function OnSeriesLoaded(args, frames) {
   _overlayManager.SetOverlayTags(frames);

   if (_userPermissions.CanViewAnnotations) {
     annotationsProxy.FindSeriesAnnotations(frames[0].Instance.SeriesInstanceUID,
         FindAnnotationsError, FindAnnotationsSuccess);
   }
}

function FindAnnotationsSuccess(annotations) {
   if (annotations && annotations.length > 0) {
      _loadedAnnotationsIds = annotations;
      EnableAnnotationLoad();
   }
   else {
      _loadedAnnotationsIds = null;
      
      DisableAnnotationLoad();
   }
}

If the image has annotations, then the load button is enabled.  Clicking the load button brings up a dialog with each set of annotations associated with the frame.  After the user selects an annotation file, the following code will get the annotation data from the server and begin adding each annotation to the canvas.

function LoadSelectedServerAnn() {
   var annID = _loadedAnnotationsIds[parseInt($($(".annItemSelected")[0]).attr("annIndex"))];

   annotationsProxy.GetAnnotations(annID.AnnotationID, GetAnnotationsError, GetAnnotationsSuccess);
}

function GetAnnotationsSuccess(annotationsData) {
   if (annotationsData) {
      try {
         var length = _automationArray.length;
         var codecs = new Leadtools.Annotations.Core.AnnCodecs();

         while (length--) {
            var frame = _dicomLoader.GetFrame(length);
            var automation = _automationArray[length];
            var container = automation.get_container();
            var destChildren = container.get_children();
            var instanceNumber = frame.Instance.InstanceNumber;

            var loadContainer = codecs.loadFromXmlDocument(annotationsData, parseInt (instanceNumber));

            if (loadContainer) {
               var srcChildren = loadContainer.get_children();
               var childrenCount = srcChildren.get_count();

               for (var i = 0; i < childrenCount; i++) {
                  var child = srcChildren.get_item(i);
                  destChildren.add(child);
               }

               automation.get_automationControl().automationInvalidate();
            }
         }

         alert("Annotations Loaded");
      }
      catch (er) {
         alert('Invalid annotations data.\n\r' + er );
      }
   }
   else {
      alert("No annotations found");
   }
}

As you can see in the next screenshot, the same image and annotations load perfectly from an iPhone.

Conclusion

LEADTOOLS provides developers with access to the world’s best performing and most stable imaging libraries in easy-to-use, high-level programming interfaces enabling rapid development of business-critical applications.

The zero footprint HTML5 DICOM Viewer is only one of the many technologies LEADTOOLS has to offer.  For more information on our other products, be sure to visit our home page, download a free fully functioning evaluation SDK, and take advantage of our free technical support during your evaluation.

Download the Full HTML5 DICOM Viewer Example

To get started with this example, you can preview it online where it is hosted on our website.  Or you can download a fully functional demo which includes the features discussed above.  To run this example you will need the following:

  • LEADTOOLS free 60 day evaluation
  • Browse to C:\LEADTOOLS 17.5\Shortcuts\HTML5\02 Medical\Medical Web Viewer
  • Execute "Run This First To Config 32-bit Demos" and at the Database Configuration Wizard screen, change the default configuration of each database to use Microsoft SQL Server (e.g. SQLEXPRESS) rather than Microsoft SQL Server Compact 3.5.  Remember the user name and password supplied because those will be used at the login screen of the demo.  Use defaults for everything else.
  • Execute "Run This Second To Configure the REST Services" and use the default options.
  • Execute "Run Web Viewer 32-bit Demo" and click "Fix Problems" if necessary to correct any differences in versions between database and IIS requirements.

Support

Need help getting this sample up and running?  Contact our support team for free technical support!  For pricing or licensing questions, you can contact our sales team (sales@leadtools.com) or call us at 704-332-5532.

For More Information on HTML5 Imaging with LEADTOOLS

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