Code Monkey home page Code Monkey logo

dicomparser's Introduction

NPM version NPM downloads MIT License Build Status Coverage Status

dicomParser

dicomParser is a lightweight library for parsing DICOM P10 byte streams, as well as raw (not encapsulated in part 10) byte streams, in modern HTML5 based web browsers (IE10+), Node.js and Meteor. dicomParser is fast, easy to use and has no required external dependencies.

Live Examples

The best way to see the power of this library is to actually see it in use. A number of live examples are included that are not only useful but also show how to use dicomParser. Click here for a list of all live examples Make sure you try out the DICOM Dump with Data Dictionary which is a very useful tool and excellent example of most features.

Community

Have questions? Try posting on our google groups forum.

Install

Get a packaged source file:

Or install via NPM:

npm install dicom-parser

Or install via atmosphere for Meteor applications

meteor add chafey:dicom-parser

  • Note - make sure you install pako if you need to support the Deflated Explicit VR Little Endian transfer syntax

Usage

// create a Uint8Array or node.js Buffer with the contents of the DICOM P10 byte stream
// you want to parse (e.g. XMLHttpRequest to a WADO server)
var arrayBuffer = new ArrayBuffer(bufferSize);
var byteArray = new Uint8Array(arrayBuffer);

try
{
    // Allow raw files
    const options = { TransferSyntaxUID: '1.2.840.10008.1.2' };
    // Parse the byte array to get a DataSet object that has the parsed contents
    var dataSet = dicomParser.parseDicom(byteArray, options);

    // access a string element
    var studyInstanceUid = dataSet.string('x0020000d');

    // get the pixel data element (contains the offset and length of the data)
    var pixelDataElement = dataSet.elements.x7fe00010;

    // create a typed array on the pixel data (this example assumes 16 bit unsigned data)
    var pixelData = new Uint16Array(dataSet.byteArray.buffer, pixelDataElement.dataOffset, pixelDataElement.length / 2);
}
catch(ex)
{
   console.log('Error parsing byte stream', ex);
}

See the live examples for more in depth usage of the library

Note that actually displaying DICOM images is quite complex due to the variety of pixel formats and compression algorithms that DICOM supports. If you are interested in displaying images, please take a look at the cornerstone library and the cornerstoneWADOImageLoader which uses this library to extract the pixel data from DICOM files and display the images with cornerstone library. You can find the actual code that extracts pixel data using this library here.

Options

dicomParser.parseDicom accepts an optional second argument that is an options object. The accepted properties are:

TransferSyntaxUID

A string value used as the default transfer syntax uid for parsing raw DICOM (not encapsualted in Part 10). For raw DICOM files, this value should be the LEI UID value.

untilTag

A tag in the form xggggeeee (where gggg is the hexadecimal group number and eeee is the hexadecimal element number, e.g. 'x7fe00010') that specifies the final tag to parse. Any tags occurring after this in the file will be ignored. Useful for partial reading of byte streams.

vrCallback

A callback that, given a tag, will return the two-character Value Representation associated with that tag (see PS 3.5 of the DICOM standard for more information). It may return undefined to indicate that the VR was not provided.

inflater

A callback that given the underlying byteArray and position of the deflated buffer returns a byteArray containing the DICOM P10 header and inflated data set concatenated together.

Key Features

  • Parses all known valid DICOM Part 10 byte arrays
    • Explicit and implicit
    • Little endian and big endian
    • Deflated Explicit VR Little Endian transfer syntax
      • Uses zlib when running node.js
      • requires pako in web browsers
      • has callback to support use of other inflate libraries
  • Supports all VR's including sequences
  • Supports elements with undefined length
  • Supports sequence items with undefined length
  • Provides functions to convert from all VR types to native Javascript types
  • Does not require a data dictionary
  • Designed for use in the browser
  • Each element exposes the offset and length of its data in the underlying byte stream
  • Packaged using the module pattern, as an AMD module and as a CommonJS module for Node.js
  • No external dependencies
  • Supports extraction of encapsulated pixel data frames
    • Basic Offset Table decoded
    • Fragments decoded
    • Function to extract image frame when basic offset table is present
    • Function to extract image frame from fragments when no basic offset table is present
  • Convenient utility functions to parse strings formatted in DA, TM and PN VRs and return JavaScript objects
  • Convenient utility function to create a string version of an explicit element
  • Convenient utility function to convert a parsed explicit dataSet into a javascript object
  • Convenient utility function to generate a basic offset table for JPEG images
  • Supports reading incomplete/partial byte streams
    • By specifying a tag to stop reading at (e.g. parseDicom(byteArray, {untilTag: "x7fe00010"}); )
    • By returning the elements parsed so far in the exception thrown during a parse error (the elements parsed will be in the dataSet property of the exception)
  • Supports reading from Uint8Arrays and Node.js Buffers

Build System

This project uses Webpack to build the software.

Pre-requisites:

NodeJs - click to visit web site for installation instructions.

Common Tasks

Update dependencies (after each pull):

npm install

Running the build:

npm run build

Automatically running the build and unit tests after each source change:

npm run watch

Publish

This library uses semantic-release to publish packages. The syntax of commits against the master branch determine how the new version calculated.

Example Commit Release Type
fix(pencil): stop graphite breaking when too much pressure applied Patch Release
feat(pencil): add 'graphiteWidth' option Feature Release
perf(pencil): remove graphiteWidth option

BREAKING CHANGE: The graphiteWidth option has been removed. The default graphite width of 10mm is always used for performance reasons.
Major Breaking Release

Backlog

Future:

  • Add unit tests for sequence parsing functionality and encapsulated pixel frames
  • Figure out how to automatically generate documentation from the source (jsdoc)
  • Optimize findItemDelimitationItemAndSetElementLength() for speed
  • Optimize functions in byteArrayParser.js for speed
  • Add example that allows you to compare two sop instances against each other
  • Figure out how to not have a global dicomParser object when used with an AMD loader
  • See what needs to be done to support different character sets (assumes ASCII currently)
  • Support for parsing from streams on Node.js and Meteor
  • Switch to JavaScript ES6
  • Separate the parsing logic from the dataSet creation logic (e.g. parsing generates events which dataSet creation logic creates the dataSet from). Similar concept to SAX parsers.
    • dataSet creation logic could filter out unwanted tags to improve performance of parse
    • dataSet creation logic could defer creation of sequence dataSets to improve performance of parse
  • Function to parse non P10 byte streams given the byte stream and the transfer syntax
  • Support for encrypted dicom

Contributors

  • @neandrake for help with getting Node.js support
  • @ggerade for implementing support for floats/doubles with VM > 1
  • @yagni for bug fix related to parsing implicit little endian files and big endian support
  • @snagytx, @doncharkowsky - for bug fix related to reading encapsulated frames
  • @bbunderson, @jpambrun - bug fix for reading encapsulated frames
  • @henryqdineen, [email protected] - bug report for sequences with undefined lengths and zero items
  • @swederik - bug fixes on sequences with undefined lengths and zero items
  • @jkrot - performance enhancement in byteArrayParser
  • @cancan101 - issue related to multi-frame with multiple fragments and no basic offset table

Why another Javascript DICOM parsing library?

While building the WADO Image Loader for cornerstone, I couldn't find a Javascript DICOM parser that exactly met my needs. DICOM really isn't that hard to parse so I figured I would just make my own. Here are some of the key things that I really wanted out of a DICOM library that I am hoping to deliver:

  • License is extremely liberal so it could be used in any type of project
  • Only deals with parsing DICOM - no code to actually display the images
  • Designed to work well in a browser (modern ones at least)
  • Follows modern javascript best practices
  • Has documentation and examples on how to use it
  • Does not hide the underlying data stream from you
  • Does not require a data dictionary
  • Decodes individual elements "on demand" - this goes with not needing a data dictionary
  • Code guards against corrupt or invalid data streams by sanity checking lengths and offsets
  • Does not depend on any external dependencies - just drop it in and go
  • Has unit tests
  • Code is easy to understand

Interested in knowing why the above goals are important to me? Here you go:

License is extremely liberal so it could be used in any type of project

DICOM is an open standard and parsing it is easy enough that it should be freely available for all types of products - personal, open source and commercial. I am hoping that the MIT license will help it see the widest possible adoption (which will in the end help the most patients). I will dual license it under GPL if someone asks.

Only deals with parsing DICOM - no code to actually display the images

I am a big believer in small reusable pieces of software and loose coupling. There is no reason to tightly couple the parser with image display. I hope that keeping this library small and simple will help it reach the widest adoption.

Designed to work well in a browser (modern ones at least)

There are some good javascript DICOM parsing libraries available for server development on node.js but they won't automatically work in a browser. I needed a library that let me easily parse WADO responses and I figured others would also prefer a simple library to do this with no dependencies. The library does make use of the ArrayBuffer object which is widely supported except for IE (it is available on IE10+). I have no current plans to add support for older versions of IE but would be open to contributions if someone wants to do the work.

Follows modern javascript best practices

This of course means different things to different people but I have found great benefit from making sure my javascript passes jshint and leveraging the module pattern. I also have a great affinity to AMD modules but I understand that not everyone wants to use them. So for this library I am shooting for simply making sure the code uses the module pattern and passes jshint.

Has documentation and examples on how to use it

Do I really need to convince you that this is needed?

Does not hide the underlying data stream from you

I have used many DICOM parsing libraries over the years and most of them either hide the underlying byte stream from you or make it difficult to access. There are times when you need to access the underlying bytes - and it is frustrating when the library works against you. A few examples of the need for this include UN VR's, private attributes, encapsulated pixel data and implicit little endian transfer syntaxes (which unfortunately are still widely being used) when you don't have a complete data dictionary.

This library addresses this issue by exposing the offset and length of the data portion of each element. It also defers parsing (and type converting) the data until it is actually asked to do so. So what you get from a parse is basically a set of pointers to where the data for each element is in the byte stream and then you call the function you want to extract the type you want. An awesome side effect of this is that you don't need a data dictionary to parse a file even if it uses implicit little endian. It also turns out that parsing this way is very fast as it avoids doing unneeded type conversions.

Note that you cannot 100% reliably parse sequence elements in an implicit little endian transfer syntax without a data dictionary. I therefore strongly recommend that you work with explicit transfer syntaxes whenever possible. Fortunately most Image Archives should be able to give you an explicit transfer syntax encoding of your sop instance even if it received it in implicit little endian.

Note that WADO's default transfer syntax is explicit little endian so one would assume that an Image Archive supporting WADO would have a good data dictionary management system. Initially I wasn't going to support parsing of implicit data at all but decided to mainly for convenience (and the fact that many of my test data sets are in little endian transfer syntax and I am too lazy to convert them to explicit transfer syntax).

Does not require a data dictionary

As a client, you usually you know which elements you want to access and know what type they are so designing a client oriented parser around a data dictionary is adding unnecessary complexity, especially if you can stick to explicit transfer syntaxes. I also believe it is the the server's responsibility to provide the client safe and easily digestable data (i.e. explicit transfer syntaxes). A server typically supports many types of clients so it makes sense to centralize data dictionary management in one place rather than burden each client with it.

Data dictionaries are not required for most client use cases anyway so I decided not to support it in this library at all. For those use cases that do require a data dictionary, you can layer it on top of this library. An example of doing so is provided in the live examples. If you do want to know the VR, request the instance in an explicit transfer syntax and you can have it. If your Image Archive can't do this for you, get a new one - seriously.

Decodes individual elements "on demand" - this goes with not needing a data dictionary

See above, this is related to not requiring a data dictionary. Usually you know exactly what elements you need and what their types are. The only time this is not the case is when you are building a DICOM Dump utility or you can't get an explicit transfer syntax and have one of those problematic elements that can be either OB or OW (and you can usually figure out which one it is without the VR anyway)

Code guards against corrupt or invalid data streams by sanity checking lengths and offsets

Even though you would expect an Image Archive to never send you data that isn't 100% DICOM compliant, that is not a bet I would make. As I like to say - there is no "DICOM police" to penalize vendors who ship software that creates bytes streams that violate the DICOM standard. Regardless, it is good practice to never trust data from another system - even one that you are in full control of.

Does not depend on any external dependencies - just drop it in and go

Sort of addressed above as maximizing adoption requires that the library minimize the burden on its users. I did find a few interesting libraries that were targeted at making it easier and safer to parse byte streams but they just seemed like overkill so I decided to do it all in one to keep it as simple as it could be. In general I am a big fan of building complex systems from lots of smaller simpler pieces. Some good references on this include the microjs site and the cujo.js manifseto

Has unit tests

I generally feel that units tests are often a waste of time for front end development. Where unit tests do make sense is code that is decoupled from the user interface - like a DICOM parsing module. I did use TDD on this project and had unit tests covering ~ 80% of the code paths passing before I even tried to load my first real DICOM file. Before I wrote this library, I did a quick prototype without unit tests that actually took me much less time (writing tests takes time....). So in the end I don't think it saved me much time getting to a first release, but I am hoping it will pay for itself in the long run (especially if this library receives wide adoption). I also know that some people out there won't even look at it unless it has good test coverage.

Interesting note here - I did not write unit tests for sequence parsing and undefined lengths mainly because I found the standard difficult to understand in these areas and didn't want to waste my time building tests that were not correct. I ended up making these work by throwing a variety of data sets at it and fixing the issues that I found. Getting this working took about 3x longer than everything else combined so perhaps it would have been faster if I had used TDD on this part.

Code is easy to understand

In my experience, writing code that is easy to understand is far more important than writing documentation or unit tests for that code. The reason is that when a developer needs to fix or enhance a piece of code, they almost never start with the unit tests or documentation - they jump straight into the code and start thrashing about in the debugger. If some other developer is looking at your code, you probably made a mistake - either a simple typo or a design issue if you really blew it. In either case, you should have mercy on them in advance and make their unenviable task of fixing or extending your code the best it can be. Some principles I try to follow include:

  • Clear names for source files, functions and variables. These names can get very long but I find that doing so is better than writing comments in the source file
  • Small source files. Generally I try to keep each source file to under 300 lines or so. The longer it gets, the harder it is to remember what you are looking at
  • Small functions. The longer the function is, the harder it is to understand

You can find out more about this by googling for "self documenting code"

In the Wild

Copyright

Copyright 2016 Chris Hafey [email protected]

dicomparser's People

Contributors

andrebot avatar chafey avatar dannyrb avatar dependabot[bot] avatar emfol avatar galelis avatar ggerade avatar ghetolay avatar henryqdineen avatar jmannau avatar kmannislands avatar kofifus avatar liamcarter111 avatar lscoder avatar malaterre avatar michaelkreil avatar sedenardi avatar shivasuri avatar sirrrich avatar snagytx avatar swederik avatar toymachiner62 avatar troyastorino avatar wayfarer3130 avatar wlogsky666 avatar yagni avatar zaid-safadi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dicomparser's Issues

Set default transfer syntax in options

Would it make sense to add a "defaultTransferSyntax" as an option?

The use case it that some custom made DICOM files do not contain this required field so DicomParser just returns an error.

Having an option would let the user "help" dicomParser to do the work:
https://github.com/chafey/dicomParser/blob/master/src/parseDicom.js#L26

if(metaHeaderDataSet.elements.x00020010 === undefined && !this.option && !this.options.defaultTransferSyntax)

Please let me know if that makes sense and I'll submit a pull request.

Does it have any other implications that I am missing?

How do I use dicomParser in node?

Is there any way to use dicomParser in node.js? The documentation doesn't mention it. On a related note, it would be great to publish the package on npm, which I'd be happy to help if needed.

(cc @juanprietob)

Encapsulated Data Without End Delimiter

I have several DICOM images that use encapsulated JPEG, but the pixel-element length is the actual length and not "4294967295". The following change to "dicomParser.readDicomElementExplicit" allows these to be read correctly:

        //if(element.length === 4294967295)
        //{
            if(element.tag === 'x7fe00010') {
                dicomParser.findEndOfEncapsulatedElement(byteStream, element, warnings);
                return element;
            }   else if(element.vr === 'UN') {
                dicomParser.findAndSetUNElementLength(byteStream, element);
                return element;
            } else if(element.length === 4294967295) {
                dicomParser.findItemDelimitationItemAndSetElementLength(byteStream, element);
                return element;
            }
        //}

Is this the best way to do this, and can we get this (or an equivalent change) accepted into the library?

Found Issue with readFragmentsUntil Function

The while loop is using byteStream.length instead of byteStream.byteArray.length for the readFragmentsUntil function which causes JPEG2000 images to fail :

function readFragmentsUntil(byteStream, endOfFrame) {
        // Read fragments until we reach endOfFrame
        var fragments = [];
        var bufferSize = 0;
        // Use byteStream.byteArray.length instead of byteStream.length to avoid exception / blowing up
        while (byteStream.position < endOfFrame && byteStream.position < byteStream.byteArray.length) {
            var fragment = dicomParser.readSequenceItem(byteStream);
            // Omitted for brevity

(I did not want to make a pull request for just a single line of code. Maybe you can address on your next update.)

Big endian parse issue?

Today I swapped the metaHeaderDataSet and instanceDataSet parameters in mergeDataSets() in an attempt to put the P10 header before the rest of the instance. This did work, but it caused one of the big endian tests to fail. On further investigation, it appears that instance items were in the metaHeaderDataSet with incorrect values (thus swapping them caused the test to fail). I don't know if the issue is with the test or the big endian parser itself

Anonymize DICOM files with javascript

I'm triying to anonymize dcm (dicom) files before uploading it to the server.

I want to do it on the client side using javascript. But I can't find more that dicom viewers.

I searched about the tags of dicom and I have found a lot of tools for remove metadata tags using python, java and ruby, but I don't know how to portrait it to javascript.

I have even decided what tags I would remove, but I'm not sure about how to do it.

Any ideas about?

Thanks for your time

Handling DICOM with empty Sequence

I ran into an issue where I have a DICOM file with an empty Sequence and the dicomParser is returning and incomplete data set.

In the case of an empty sequence the findItemDelimitationItemAndSetElementLength function will never find the ItemDelimitationItem and reads until the end of the stream.

I wonder if we can modify the code to stop reading if it finds a SequenceDelimitationItem and move on to other elements. Let me know if you think that makes sense or if I have some misunderstanding about how DICOM works in this case.

Thanks so much,

Henry Q. Dineen

Dicom writer

I'm trying to implement DICOM manipulation and was wondering if there was any interest in making dicomParser capable of manipulating the data and storing to a buffer.

Getting: Error parsing byte stream RangeError: Invalid typed array length: ####

I'm trying to use the simple example to read in a dicom file and display it on the page using cornerstone and the cornerstoneWADOImageLoader libraries. I have this working fine using regular files and the wado fileuri loader, but I'm trying to get it working with byte arrays so I can do work with it with server-processed data. The simple example is throwing an error based on an incorrect Uint16Array length, I believe. Does anyone see anything wrong with this code?

const reader = new FileReader();
reader.addEventListener('load', (e) => {
    let pixelData = self.loadP10Data(reader.result);
    dicomImageData['example://1'] = pixelData;
    self.loadAndViewP10Image('example://1');
}, false);

reader.readAsArrayBuffer(file);

loadP10Data(readerResult) {
    const self = this;
    try
    {
        let byteArray = new Uint8Array(readerResult);

        // Parse the byte array to get a DataSet object that has the parsed contents
        var dataSet = dicomParser.parseDicom(byteArray/*, options */);

        // get the pixel data element (contains the offset and length of the data)
        var pixelDataElement = dataSet.elements.x7fe00010;

        // create a typed array on the pixel data (this example assumes 16 bit unsigned data)
        // FAILS HERE:
        var pixelData = new Uint16Array(dataSet.byteArray.buffer, pixelDataElement.dataOffset, pixelDataElement.length);

        return pixelData;
    }
    catch(ex)
    {
        console.log('Error parsing byte stream', ex);
    }
    return '';
}

Error:

Got pixel data {tag: "x7fe00010", vr: "OW", length: 89456, dataOffset: 2098, hadUndefinedLength: true, …}
app.js:56571 LENGTH 89456
app.js:56577 Error parsing byte stream RangeError: Invalid typed array length: 89456
at typedArrayConstructByArrayBuffer ()
at new Uint16Array (native)
at StringBase64DicomFile.loadP10Data (http://localhost:3000/app.js:56573:29)
at FileReader.reader.addEventListener (http://localhost:3000/app.js:56539:26)

ESLint warnings

I compiled the last version with webpack and there is many warnings (no-throw-literal, vars-on-top, func-style, init-declarations, no-param-reassign, ...).

Is it normal ? Are we dropping ESLint checking ?

Helper function to select correct byteArrayParser?

I was wondering in particular how to make use of the following Key Features:

  • Each element exposes the offset and length of its data in the underlying byte stream
  • Supports reading incomplete/partial byte streams
    • By specifying a tag to stop reading at

This code will get me just the values:

var dicom = dicomParser.parseDicom(byteArray);
var patientName = dicom.string('x00100010');
var patientId = dicom.string('x00100020');

But how do I get the positions of those elements in the byte stream?

I found this method dicomParser.readDicomElementImplicit = function(byteStream, untilTag) in your source but the comments say that it's an "Internal helper functions for for parsing DICOM elements" and I can't really figure out how to construct the required dicomParser.ByteStream = function(byteArrayParser, byteArray, position) object because there is no helper function to determine the correct object to instantiate for the byteArrayParser argument.

Please help? :)

doesn't parse encapsulated PDF

Raises error "Unhandled Promise Rejection: TypeError: undefined is not an object (evaluating 'pixelDataElement.encapsulatedPixelData')" If DICOM file is of 1.2.840.10008.5.1.4.1.1.104.1 SOP class (encapsulated PDF) because such files have encapsulated data stream in tag x00420011 while dicomParser checks for data only in tags x7fe00010 and x7fe00008 (getPixelData.js, function getPixelData).

Data Dictionary

I feel like as long as the lookahead in readDicomElementImplicit.js remains, it feels like there's a snake in the grass in the code. While it works for the majority of time (I've never encountered it failing), it gives me this niggling feeling that at any time my code could fail, potentially silently which would be even scarier.

I'd like to implement a data dictionary, but I don't want to force it on everyone. Chris, what do you think about me putting it in a separate file that the user can choose to include if desired? I can add another grunt step so it will build in to the distribution seamlessly. I just wanted to solicit your thoughts before going forward with it.

getPixelDataFromFragments - Bad Uint8Array initialization

I found a strange behavior in the case of a single fragment and a new Uint8Array is crated as a view of the dicom object byteStream: the new array is misaligned from the source buffer.
In my case the new array is two bytes ahead: fragments[0].dataOffset is 2056, the new array starts at byte 2054 of the byteStream. Length is correct.
I found this behavior using Safari on Mac OS X, Chrome and Firefox on Ubuntu Linux x64, Chrome on Windows 7 x64. Could be a dword alignment? but 2056 is at dword boundaries!
The work around I applied is to comment the if( fragments.lenght === 1) condition.

Do you have any workarround for non P10 DICOM?

Hello
I have used you library for a project and now I want to add P10 parsing and modifying.
I have found some instruction you gave to another user ( #12 ) but I have not managed to do it.
Do you have any further instruction or this is the only steps?
Thanks in advance
Dimtiris

[Question] Are tags that are not part of the standard included as elements in the dataset after parseDicom is called?

Hi, I just started using dicomParser with the dicom dump example. I'm working with a derivative standard that has additional tags, and I'm wondering whether the tags not known to DICOM would still show up as elements in the dataset. I'm new to both DICOM and the derivative standard, so I don't know the additional tags yet, and the dump shows elements with tags known only to DICOM. This is also true when console logging the dataset. It's possible that the image I uploaded doesn't include any unknown tags, but I wanted to be sure whether they would show up or not if included.

Thanks.

Add VR in Implicit Dataset?

Since we have the vrCallback now, would it make sense to add vr to the element within readDicomElementImplicit with the return value from the vrCallback (if provided)? I can do this.

Memory Leak in Parsing

https://github.com/chafey/dicomParser/blob/34c02a7cec6b71a68ae21856029a8f5d957e900e/src/readSequenceElementExplicit.js

So I have been doing tests for parsing 1000+ files and I keep running into a memory leak/ inefficient garbage collection happening with these functions. It is making out my heap and causing the parsing to crawl waiting for garbage collection to finish. I was wondering if anyone else ran into this problem. Also I think I may be able to fix the underlying issue but I might need to talk it through with @chafey

parseTM does not parse fractional seconds properly

ParseTM parses out the fractional portion of the time stamp using a straight parseInt, causing '.5' and '.000005' to result in the same value of 5 microseconds. TM allows anywhere from 1 to 6 digits to be provided so parseTM needs to consider the actual number of digits present in the fractional component and multiply by the appropriate power of 10. Could also zero right-pad then parse but that would probably be the most expensive/wasteful option.

publish new version to npm

We are using this in our node project but version 1.0.1 on npm doesn't have the fix from PR #15.

Can you re-publish to npm or publish a new version?

Thanks in advance.

Some comments regarding the byteArrayParser.js

I have had a look at some functions in your code. In particular, since you have some comments (something like: "I am sure there is a better way than this but this should be safe") in your functions dicomParser.readFloat() and dicomParser.readDouble(), I was thinking that it was possible to get some performance gain in these functions.

Before submitting any proposal of changes, I have done some tests using the jsperf website. My intention was to suggest using the subarray method available on the typed arrays instead of copying every single byte. The goal of doing previously these tests was not to make the same mistake as I did when I decided to use the DataView class on my code (more information here)

Here you can have a look at the results: http://jsperf.com/readfloat

In short: right now, copying bytes seems to be the best solution.

Commit breaks my code :(

Hi Chris, the following commit is breaking my code:

https://github.com/yagni/dicomParser/blob/a512e23b6d0cf83fafcbde96cae7df0d2087d282/dist/dicomParser.js

It throws this exception on all the files I've test:

dicomParser.readSequenceItem: item tag (FFFE,E000) not found at offset 61502

As I understand it checks for FFFE,E000 after every "SQ", but I'm not sure if this is correct. For example, please see this dump:

# Dicom-Data-Set
# Used TransferSyntax: JPEG Lossless, Non-hierarchical, 1st Order Prediction
(0008,0005) CS [ISO_IR 100]                             #  10, 1 SpecificCharacterSet
(0008,0008) CS [DERIVED\PRIMARY]                        #  16, 2 ImageType
(0008,0016) UI =DigitalXRayImageStorageForPresentation  #  28, 1 SOPClassUID
(0008,0018) UI [40.113845.11.1000000001951524609.20160323200435.3393292.3.54811] #  64, 1 SOPInstanceUID
(0008,0020) DA [20160323]                               #   8, 1 StudyDate
(0008,0023) DA [20160323]                               #   8, 1 ContentDate
(0008,0030) TM [201546]                                 #   6, 1 StudyTime
(0008,0033) TM [201703]                                 #   6, 1 ContentTime
(0008,0050) SH [290235.13]                              #  10, 1 AccessionNumber
(0008,0060) CS [CR]                                     #   2, 1 Modality
(0008,0068) CS [FOR PRESENTATION]                       #  16, 1 PresentationIntentType
(0008,0070) LO [Sirona]                                 #   6, 1 Manufacturer
(0008,0080) LO [Institution]                       #  16, 1 InstitutionName
(0008,0090) PN [.]                                      #   2, 1 ReferringPhysicianName
(0008,1010) SH [Puestoortophan]                         #  14, 1 StationName
(0008,1030) LO [CONDILOGRAFIA]                          #  14, 1 StudyDescription
(0008,1070) PN (no value available)                     #   0, 0 OperatorsName
(0008,1090) LO [ORTHOPHOS XG]                           #  12, 1 ManufacturerModelName
(0008,1120) SQ (Sequence with explicit length #=0)      #   0, 1 ReferencedPatientSequence
(fffe,e0dd) na (SequenceDelimitationItem for re-encod.) #   0, 0 SequenceDelimitationItem
(0008,2111) ST [Lossless JPEG compression, selection value 1, point transform 0, c... #  90, 1 DerivationDescription
(0008,2218) SQ (Sequence with explicit length #=1)      #  48, 1 AnatomicRegionSequence
  (fffe,e000) na (Item with explicit length #=3)          #  40, 1 Item
    (0008,0100) SH [T-D1100]                                #   8, 1 CodeValue
    (0008,0102) SH [SNM3]                                   #   4, 1 CodingSchemeDesignator
    (0008,0104) LO [Head]                                   #   4, 1 CodeMeaning
  (fffe,e00d) na (ItemDelimitationItem for re-encoding)   #   0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem for re-encod.) #   0, 0 SequenceDelimitationItem

As you can see, there are some tags (0008,1120 for example) that are sequences with length=0, so, no FFFE,E000 after them, but in all cases, SQ values end with an FFFE,E0DD tag.

Correct me if I'm wrong but I think the right behavior should be this:

(0008,1120)
    # here can be an FFFE,E000 finished with FFFE,E00D or nothing (0.."n" multiplicity) 
(fffe,e0dd)

So, the line 2211 I think should be replaced by:

if ( (element.tag !== 'xfffee000') && (element.tag !== 'xfffee0dd') )

What do you think?.

Error in 0.js from UglifyJs, unexpected character '`', angular 4 with dotnet core

I'm facing an issue file publishing my dotnet core Angular app
Error MSB3073 :
nodeerror
because of the following issue
publishissue

which is at
0jserror

this is the readTag method in the dicom-parser component which I am using to render dicom-images using cornerstone component.
this is my package.json
packageuglify

and webpack
webpack

Can any one put thoughts into it as it is from the dicom-parser
not be able to minified my UglifyJs which is causing the Issue.

dicomParser is case sensitive

This may be intended behavior, but
var studyInstanceUid = dataSet.string('x0020000D'); will result in undefined whereas:
var studyInstanceUid = dataSet.string('x0020000d'); will store the tag value as expected.

Dicom Parser Parsing Error

So I am having problems parsing a dicom file, it is possible that the anonymization before it was sent to me is causing the issue but I can't figure out why the parser is failing. I have used some other dicomParsing and they are able to be viewed fine. I get a Uncaught # and the error is getting thrown here. I have zipped the file so you can replicate, all patient data is bogus.

image_0001.dcm.zip

function readDataSet(metaHeaderDataSet)
    {
        var transferSyntax = readTransferSyntax(metaHeaderDataSet);
        var explicit = isExplicit(transferSyntax);
        var dataSetByteStream = getDataSetByteStream(transferSyntax, metaHeaderDataSet.position);

        var elements = {};
        var dataSet = new dicomParser.DataSet(dataSetByteStream.byteArrayParser, dataSetByteStream.byteArray, elements);
        dataSet.warnings = dataSetByteStream.warnings;

        try{
            if(explicit) {
                dicomParser.parseDicomDataSetExplicit(dataSet, dataSetByteStream, dataSetByteStream.byteArray.length, options);
            }
            else
            {
                dicomParser.parseDicomDataSetImplicit(dataSet, dataSetByteStream, dataSetByteStream.byteArray.length, options);
            }
        }
        catch(e) {
            var ex = {
                exception: e,
                dataSet: dataSet
            };
            throw ex;
        }
        return dataSet;
    }

readEncapsulatedPixelData not available in dicomParser.js

Hi Chris,

First of all thanks for the great library -

I am trying to read encapsulated pixelData in order to decompress it but it seems is is not exposed in the uglified dicomParser.js:

var compressedPixelData = dicomParser.readEncapsulatedPixelData(
    this._dataSet,
    this._dataSet.elements.x7fe00010,
    frameIndex);

returns:

'undefined' is not a function

How are we supposed readEncapsulatedPixelData with dicomParser? I was following what is done in the cornerstone WADO loader.

Also, as a related question, why do we have to provide the frameIndex to decompress the pixelData? Does it automatically return the frame of interest if we have a muti-frame dataset?

Is it possible to extract all the pixelData at once, in the case of a multi-frame dataset, and split it later if needed, or is it not recommended?

Thanks
Nicolas

dicomParser Does not work with electron.

DicomParser should be declared as a browser global object in the case where it's used as a node module. ElectronJS uses both node modules and bower components, therefore dicomParser should be declared as a global

/*! dicom-parser - v1.6.1 - 2016-05-24 | (c) 2014 Chris Hafey | https://github.com/chafey/dicomParser */
(function (root, factory) {

    // node.js
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = factory();
        dicomParser = factory();
    }
....

PixelData

Hi,
how can i retrieve the pixel data in the x7fe00010 tag with your parser?

Big Endian Support

Hi Chris,

In #6 you mention you're working with jap1968 on the design for big endian support. I'm interested in that feature and willing to implement it or help implement it. What can I do to help get that in the code base?

Thanks,
Bryan

Parse contour dara in rtss dicom

How can I get contour data in rtss dicomFile?
I'm using http to get a rtss file from server client and parse it by dicomParser.js, then I should get the contour data by tag '30060050', bind with ct image and show rtss image over ct image in browser;
however the result is string , which split by '', the '' is an escape character,is ignored,so I can't change it
into array and can not get the z position.

Thanks sincerely!

dicomParser.readFixedString = function (byteArray, position, length) {
if (length < 0) {
throw 'dicomParser.readFixedString - length cannot be less than 0';
}

        if (position + length > byteArray.length) {
            throw 'dicomParser.readFixedString: attempt to read past end of buffer';
        }

        var result = "";
        var byte;
        for (var i = 0; i < length; i++) {
            byte = byteArray[position + i];
            if (byte === 0) {
                position += length;
                return result;
            }
            result += String.fromCharCode(byte);
        }

        return result;
    };

ROIContourSequence :
Item #0 xfffee000
ContourSequence :
Item #0 xfffee000
ContourData : "-225.05-124.07-122.44-222.9-124.73-122.44-220.75-124.98-122.44-218.6-125.06-122.44-216.46-125.12-122.44-214.31-125.17-122.44-212.16-125.17-122.44-210.01-125.12-122.44-207.86-125.12-122.44-205.71-125.12-122.44-203.56-125.06-122.44-201.42-125.12-122.44-199.27-125.12-122.44-197.12-125.12-122.44-194.97-125.17-122.44-192.82-125.17-122.44-190.67-125.07-122.44-188.53-124.87-122.44-186.38-124.18-122.44-185.87-123.85-122.44-184.23-121.91-122.44-184.13-121.7-122.44-183.77-119.56-122.44-183.79-117.41-122.44-184.03-115.26-122.44-184.23-114.58-122.44-184.77-113.11-122.44-186.38-111.1-122.44-186.57-110.96-122.44-188.53-110.04-122.44-190.67-109.59-122.44-192.82-109.4-122.44-194.97-109.34-122.44-197.12-109.33-122.44-199.27-109.33-122.44-201.42-109.33-122.44-203.56-109.28-122.44-205.71-109.24-122.44-207.86-109.18-122.44-210.01-109.14-122.44-212.16-109.09-122.44-214.31-109.09-122.44-216.46-109.08-122.44-218.6-109.09-122.44-220.75-109.1-122.44-222.9-109.27-122.44-225.05-109.77-122.44-227.2-110.86-122.44-227.32-110.96-122.44-228.84-113.11-122.44-229.35-114.9-122.44-229.43-115.26-122.44-229.49-117.41-122.44-229.35-118.3-122.44-229.12-119.56-122.44-228.05-121.7-122.44-227.2-122.66-122.44-225.47-123.85-122.44"
NumberOfContourPoints : "464"
ContourGeometricType : "CLOSED_PLANAR"
ContourImageSequence :
Item #0 xfffee000
ReferencedSOPInstanceUID : "2.16.840.1.113662.2.12.0.3057.1241703565.529"
ReferencedSOPClassUID : "1.2.840.10008.5.1.4.1.1.2" [ CT Image Storage ]

Address npm dependency issues found in master branch

DEV DEPENDENCIES

  • grunt-contrib-qunit
    Requested: ^0.4.0 | Latest: 0.7.0
    OUTDATED INSECURE
    semver Regular Expression Denial of Service
    Found in sub-dependency: grunt-contrib-qunit (0.4.0) → grunt-lib-phantomjs (0.5.0) → semver (1.0.14)
  • grunt-contrib-watch
    Requested: ^0.6.1 | Latest: 0.6.1
    INSECURE
    qs Denial-of-Service Extended Event Loop Blocking
    Found in sub-dependency: grunt-contrib-watch (0.6.1) → tiny-lr-fork (0.0.5) → qs (0.5.6)
    qs Denial-of-Service Memory Exhaustion
    Found in sub-dependency: grunt-contrib-watch (0.6.1) → tiny-lr-fork (0.0.5) → qs (0.5.6)
  • load-grunt-tasks
    Requested: ^0.2.1 | Latest: 3.2.0
    OUTDATED
  • grunt-contrib-concat
    Requested: ^0.3.0 | Latest: 0.5.1
    OUTDATED
  • grunt-contrib-clean
    Requested: ^0.5.0 | Latest: 0.6.0
    OUTDATED
  • grunt-contrib-copy
    Requested: 0.4.x | Latest: 0.8.0
    OUTDATED
  • grunt-contrib-jshint
    Requested: ^0.8.0 | Latest: 0.11.2
    OUTDATED
  • grunt-contrib-uglify
    Requested: ^0.4.0 | Latest: 0.9.1
    OUTDATED

toDA an toTM should do more validation

And perhaps throw an exception if invalid (perhaps by flag). Some examples of bad dates that this function should guard against:

dicomParser.parseDA('20150001'); // 00 is invalid month
dicomParser.parseDA('20150100'); // 00 is invalid day
dicomParser.parseDA('201500AA'); // AA is invalid day, returns NaN

dicomParser skips PixelData if it can not determine the length of an unknown tag

I have an issue with a dicom file that has an unknown tag before Pixel Data. dicomParser tries to determine the length of this unknown tag and checks only ItemDelimitationItem (fffe, e00d), not SequenceDelimitationItem (fffe, e0dd), so it can not determine its length and sets its length to the end of the buffer, so skips Pixel Data.

My quick fix is that i check SequenceDelimitationItem in findItemDelimitationItemAndSetElementLength, but not sure if that is a good fix.

if(elementNumber === 0xe00d || elementNumber === 0xe0dd) { ... }

This is the end of its dicom dump which shows the unknown tag and Pixel Data:

(0507,1001) SQ (Sequence with undefined length #=1) # u/l, 1 Unknown Tag & Data
(fffe,e000) na (Item with explicit length #=8) # 74, 1 Item
(0507,0000) UL 62 # 4, 1 PrivateGroupLength
(0507,1002) ?? (no value available) # 0, 1 Unknown Tag & Data
(0507,1003) ?? (no value available) # 0, 1 Unknown Tag & Data
(0507,1004) ?? (no value available) # 0, 1 Unknown Tag & Data
(0507,1005) ?? 30\20 # 2, 1 Unknown Tag & Data
(0507,1006) ?? 30\20 # 2, 1 Unknown Tag & Data
(0507,1007) ?? (no value available) # 0, 1 Unknown Tag & Data
(0507,1008) ?? 30\20 # 2, 1 Unknown Tag & Data
(fffe,e00d) na (ItemDelimitationItem for re-encoding) # 0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem
(7fe0,0010) OB (PixelSequence #=2) # u/l, 1 PixelData
(fffe,e000) pi (no value available) # 0, 1 Item
(fffe,e000) pi ff\d8\ff\c3\00\0b\10\06\01\03\04\01\00\11\00\ff\c4\00\24\00\00\00... # 1250014, 1 Item
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem

I can not share the file, because anonymization tools remove that unknown tag.

Handling truncated DICOM

Thanks for this great package.

Some DICOM doesn't have 128 byte 00H preamble and DCIM string, see
http://nipy.org/nibabel/dicom/spm_dicom.html

Now parseDicom simply judges this file as non-DICOM and throws exception, but it is convenient if parseDicom accepts truncated DICOM.

The implementation is very easy, just seeking back to the file head and setting the transfer syntax to default (1.2.840.10008.1.2).
More eager check may be preferable though.

I've already implemented (without eager check though).
If you think parseDicom should be able to handle truncated DICOM, I'll send a pull request.

Npm package 1.8 is not working.

The node package is broken. I get :

ReferenceError: window is not defined

(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory();
	else if(typeof define === 'function' && define.amd)
		define("dicom-parser", [], factory);
	else if(typeof exports === 'object')
		exports["dicom-parser"] = factory();
	else
		root["dicomParser"] = factory();
})(window, function() {   // <==== HERE
return /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

I suppose this is probably due to the change to webpack 4? At least one node test case should probably be included..

Anonymize dicom

Could it be possible to use this library to anonymize certain tags of a dicom file?

I've tried to use the explicitDataSetToJS function, in order to locate and de-identificate the patient name, but once I have the new json object I don't know how to convert it into a dicom file again.

Thank you.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.