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

Accessing Medical Records on Android™ Mobile Devices

21 Aug 2012 1  
The emergence of this new class of hardware creates an opportunity for doctors and medical professionals to access patient data wherever they are. This whitepaper will focus on the AIMTools SDK, Barcode Xpress Mobile SDK and accessing medical records on Android mobile devices.

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.

New Android mobile devices are coming to market at a very rapid pace.The emergence of this new class of hardware creates an opportunity for doctors and medical professionals to access patient data wherever they are. Instead of having to go to a kiosk or lug around printouts or an oversized laptop, they can use a mobile phone or a tablet device to access patient data. Accusoft Pegasus, a leader in Windows SDKs, has moved into the mobile space with exciting new offerings that give medical professionals mobile access to a wide array of medical data. This whitepaper will focus on two recent product releases and how they can be used to enable access to medical records on Android devices: AIMTools and Barcode Xpress Mobile.

Use Case: Patient Medical Records

The use of barcoded bracelets for patients is now commonplace, and for obvious reasons: it provides positive identification, even if a patient is unable to do so themselves.  This enhances patient safety and greatly reduces the chance of a medical error arising from dosing (or worse, operating on) the wrong patient. The New England Journal of Medicine recently documented a study in an article titled, "Effect of Bar-Code Technology on the Safety of Medication Administration".  The results of the study confirmed the use of barcode technology for dosing and administering patient medications led to a significant reduction in errors.

Many facilities encode patient bracelets with 1D barcodes, such as Code 128.  Code 128 is an alphanumeric symbology, which is well suited for encoding information like a patient ID or name. It can also be read easily and accurately by commonly available laser scanners.

Medical Bracelets using 1D Barcodes

First, we’ll show a 1D Barcode on a bracelet containing just a patient ID, encoded using the Code 128 symbology.  

Here’s the bracelet on a patient’s arm:

Mobile-Medical-Records/image001.jpg

And here’s Barcode Xpress Mobile for Android reading the barcode and displaying the patient ID:

Mobile-Medical-Records/image002.jpg

Using the Decoded Data

Once the barcode has been decoded, the data ("A32581239") is available for consumption by other programs.  For example, suppose this patient ID is an index to a patient record that contains images on the hospital’s server.  We can retrieve these images using the index from the barcode that was read by Barcode Xpress for Android.  Once retrieved, the images can be displayed on the mobile device. 

The Code

Android applications interact with the hardware using an event driven interface called an Activity.  The Activity model provides callbacks where actions are to be performed.  The Activity provided with Barcode Xpress Mobile exposes a number of callbacks for your use; one of them is called onBarcodeRecognition.  This callback is triggered when a barcode is recognized during scanning.

Let’s see how we can use this callback to retrieve a file.  In a real world implementation, there would be security considerations, encryption, etc. – this code fragment is intended to demonstrate just the basic capabilities of the system.

public void onBarcodeRecognition(Bundle msgBundle)
{
   // Set the state to show a successful decoding happened.
   scanState = R.id.display_results;
 
   // Extract the decoding results from the message bundle
   BXResult result = msgBundle.getParcelable("Result");
 
   // The Patient ID is encoded in the barcode
   String patientId = result.getDataString();
                     
   // Use the data to get the file
   try {
       URL url = new URL("http://www.YOUR_SITE.com/?=" + patientId + ".jpg");
       URLConnection urlConn = url.openConnection();
       InputStream is = urlConn.getInputStream();
       BufferedInputStream bis = new BufferedInputStream(is);
       ByteArrayBuffer bab = new ByteArrayBuffer(1024);
       int data = 0;
       while ((data = bis.read()) != -1) {
              bab.append((byte) data);
       }
       FileOutputStream fos = new FileOutputStream("/sdcard/" + patientId + ".jpg");
       fos.write(bab.toByteArray());
       fos.close();
                           
   } catch (MalformedURLException e) {
       e.printStackTrace();
   } catch (IOException e) {
       e.printStackTrace();
   }

Viewing Medical Images on Android

Now that your application has obtained the patient’s ID using the barcode, and retrieved images associated with that ID, you need a way to view the images.  Many of the lossless image formats used in medical imaging, including 8 through 16-bit grayscale JPEG 2000 and Lossless JPEG, are not supported natively by the Android operating system.  In order to interactively view and work with these images, they would need to be converted to a lossy supported format like JPEG. 

That is, until now.

The Accusoft Pegasus AIMTools SDK allows developers to write apps that work with the original image data without the need for conversion or round trips to a server.  This means that a native Android app can interact with all of the original image data, while de-compressing and converting the parts of the image important to the user of the application.  Window leveling, zooming and other common operations can be performed locally; there is no requirement to call back to the server.  This significantly increases the app’s responsiveness and dramatically improves the user’s experience.

The TouchExampleView Multitouch sample from the Android team forms the basis for the viewer we need to display the image returned in the patient’s record.  The sample code used for the viewer can be obtained from Android here:

Making Sense of Multitouch

In order to view a medical image in our app, we need to get a Bitmap of the original image data using JNI calls to the AIMTools native libraries.  The getBitmapNative JNI method initiates the calls to the AIMTools native libraries.  As mentioned before, AIMTools has the ability to crop, resize and adjust window level (brightness and contrast) of the original image data.  These settings are contained in the ConvertParams structure.  The implementation is as follows:

/*
 * Get a bitmap of an image (native function).
 */
JNIEXPORT jobject JNICALL Java_com_accusoft_viewer_AIMImage_getBitmapNative (JNIEnv* env,
                                                                  jobject image,
                                                                  jobject convertParams)
{
  jobject bitmap = NULL;
  AIM_IMAGE *pAimImage;
 
  /* Try to get AIM_IMAGE pointer from Java class field. */
  pAimImage = getAimImageNative(env, image);
  if (pAimImage != NULL) {
     AIM_BITMAP *pAimBitmap;
     AIM_IMAGE_CONVERT_PARAMS *pConvertParams = NULL;
     bool ok = true;
 
     /* Convert convert params to native. */
     if (convertParams != NULL) {
        pConvertParams = extractAimImageConvertParamsNative(env, convertParams);
        if (pConvertParams == NULL) {
           ok = false;
        }
     }
 
     if (ok) {
        /* Get native bitmap. */
        ok = AIMImageGetBitmap(pAimImage, &pAimBitmap, pConvertParams);
        if (ok) {
          bitmap = createAimBitmap(env, pAimBitmap);
          if (bitmap == NULL) {
             AIMBitmapDestroy(pAimBitmap);
          }
        }
        if (pConvertParams != NULL) {
            free(pConvertParams);
        }
     }
   } else {
        LOGD("AIMImage.getBitmapNative(): Could not get AIM_IMAGE from AIMImage.\n");
   }
 
   return (bitmap);
}

AIMImageGetBitmap is a C function calling directly into the native AIMTools library to return a bitmap:

/*
 * Get a bitmap of an image.
 *
 * Returns true if bitmap was created.
 * The output bitmap '*ppBitmap' MUST be destroyed by the caller.
 * If image is a container, this function will return false.
 */

 
bool AIMImageGetBitmap (AIM_IMAGE  *pImage,    /* Pointer to image. */
                        AIM_BITMAP **ppBitmap, /* Pointer to output bitmap. */
                        const AIM_IMAGE_CONVERT_PARAMS  *pConvertParams)  /* Pointer to structure describing image conversion parameters (resize, crop, brightness, contrast). */
{
    bool ok = false;
 
    if ((pImage != NULL) && (ppBitmap != NULL)) {
       /* Provide default values for output parameters. */
       *ppBitmap = NULL;
 
       if (pImage->SubImageQuantity == 0u) {
          void       *pOutputBuffer = NULL;
          size_t      outputLength = 0u;
          AIM_BITMAP *pBitmap = NULL;
          bool        convertOK = true;
          RGBQUAD     colorTbl[272];
 
          if (pConvertParams != NULL) {
             if ((pConvertParams->Brightness < AIM_IMAGE_BRIGHTNESS_MIN) ||  
                 (pConvertParams->Brightness > AIM_IMAGE_BRIGHTNESS_MAX)) {
                    convertOK = false;
             }
             if ((pConvertParams->Contrast < AIM_IMAGE_CONTRAST_MIN) || 
                 (pConvertParams->Contrast > AIM_IMAGE_CONTRAST_MAX)) {
                    convertOK = false;
             }
          }
          if (convertOK) {
             bool   bitmapOK;
             REGION region;
 
             bitmapOK = pImage->pExpander->GetBitmapFunc( pImage,
                         &pOutputBuffer, &outputLength, &region,
                         colorTbl, pConvertParams);
 
             if (bitmapOK) {
               pBitmap = AIMBitmapCreateFromDataDirect(pOutputBuffer, 
                                     outputLength, &region);
               if (pBitmap == NULL) {
                  AIM_DEBUG(("Error: AIMImageGetBitmap(): Error creating bitmap.\n"));
                  free(pOutputBuffer);
               } else {
                  ok = true;
               }
             } else {
                AIM_DEBUG(("Error: AIMImageGetBitmap(): Error extracting bitmap.\n"));
             }
           } else {
             AIM_DEBUG(("Error: AIMImageGetBitmap(): Invalid conversion paraeters.\n"));
           }
 
            *ppBitmap = pBitmap;
        } else {
          AIM_DEBUG(("Error: AIMImageGetBitmap(): Bad bitmap of image container.\n"));
        }
    } else {
        AIM_DEBUG(("Error: AIMImageGetBitmap(): Argument error.\n"));
    }
    return (ok);
}

Conclusion

Accessing patient records and viewing medical images are key components of a complete mobile EMR/EHR solution.  However, the Android environment does not natively support viewing of JPEG 2000 and Lossless JPEG images.   Mobile SDKs from Accusoft Pegasus help you overcome this limitation and build the applications your clients need in the medical space to maximize productivity.

You can find Accusoft Pegasus product downloads and features atwww.accusoft.com. Explore our barcode web demo at http://demos.accusoft.com/barcodexpressdemo to test our barcode recognition accuracy or download a trial version of our mobile barcode SDK, Barcode Xpress Mobile, at http://www.accusoft.com/barcodemobiledemo.htm. The AIMTools demo video and SDK download are available at http://www.accusoft.com/aimtools.htm.  Please contactinfo@accusoft.comfor more information.

Coming Soon.

In Part 2, we will discuss how to access medical records using iOS devices such as Apple’s iPad and iPhone products.  Accusoft Pegasus has already released AIMTools for iOS, and will release Barcode Xpress Mobile for iOS in the coming months.  We hope you’re as excited about these solutions as we are!

About Accusoft Pegasus

Accusoft Pegasus provides imaging software development kits (SDKs) that accelerate development and viewers that facilitate collaboration.Our code works reliably behind the scenes when an application calls for capturing, processing, storing and viewing images. Add barcode, compression, DICOM, image processing, OCR/ICR, forms processing, PDF, scanning, video, and image viewing to your applications. Technology is delivered for multiple 32-bit/64-bit platforms and development environments, including .NET, Silverlight, ASP.NET, iOS, Android, ActiveX, Java, Linux, Solaris, Mac OSX, and IBM AIX. Customers receive superior technical support and customer service by trained, in-house teams dedicated to help meet their needs. Find unlimited full version trial SDKs and demos at www.accusoft.com.

About the Authors

Rob Rimbold is a Senior Software Engineer with Accusoft Pegasus. He has over 20 years of multi-discipline software development experience. Rob graduated with a BSCS from The University of Lowell, MA.

Scott Wilson is a Project Manager with Accusoft Pegasus. He has had over 20 years of software development and management experience. Scott graduated with a B.Sc. from McMaster University in Hamilton, Canada.

Steve Wilson is a Product Group Director with Accusoft Pegasus. Steve is responsible for leading his team to develop new products as well as increase the feature sets within several Accusoft Pegasus product lines. He brings a strong technical background to the management team, as well as experience managing diverse offshore and onshore development teams. Steve earned a Bachelor of Science in Computer Science from the University of South Florida.

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