Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to load DICOM with no DICM preamble #188

Closed
ivmartel opened this issue Nov 19, 2015 · 10 comments
Closed

Allow to load DICOM with no DICM preamble #188

ivmartel opened this issue Nov 19, 2015 · 10 comments
Labels
enhancement New feature or request
Milestone

Comments

@ivmartel
Copy link
Owner

Some DICOM data could not have the DICM preamble. I could be interesting to try and display it anyway...

@ivmartel ivmartel added the enhancement New feature or request label Nov 19, 2015
@ivmartel ivmartel added this to the Future milestone Nov 19, 2015
@ikhsansofyan
Copy link

I found the same problem, I need to know, where I can see the dicom premeable and Prefix, thanks for your support

@ivmartel
Copy link
Owner Author

ivmartel commented Mar 2, 2018

See this SO page: validating-dicom-file.
The preamble is either there or not. And when it is there its value is 'DICM'.

@ikhsansofyan
Copy link

thanks for your help, hope I can figure out the problem

@tguiot
Copy link

tguiot commented Nov 30, 2018

I'm upping this thread (can you say that? i'm not a native speaker) because I have the same request.

in the dicomParser code right now the only thing that is required is to have the "magic" DICM at bytes 129-132. I've checked at the source code in Horos and also in Pixelmed. I tend to trust Pixelmed's strategy as it is written by David Clunie, a big head of DICOM.

In Pixelmed, there's a function "isValidDicom" that return a boolean success=true if any of the following conditions is met:

  • if bytes 129-132 = "DICM" AND if the next 2 bytes = 00 02 (a valid, very standard dicom file is supposed to start with a metaheader of the group 0002)
  • else if bytes 129-132 = "DICM" AND if the next 2 bytes = 02 00 (with bytes swapped in case it's big endian, although not allowed in principle)
  • else if length >= 8
    AND 2 first bytes = 00 08
    AND 2 next bytes <= 00 18 (the very first element should AT LEAST be the SOPInstanceUID: 0008,0018)
    AND 4 next bytes <= 100 (reasonable value length) OR 2 next bytes contain an upper case character (the VR)
  • else if same check with byte swapping for big endian

So the idea is that a file without a preamble should start with tags from group 0008 and at least the element 0018 (SOPInstanceUID). If not, David says it's not a dicom file.

Additionnally, in the absence of a meta header, you have to guess the transfer syntax, implicit or explicit? there's some guess work to be done, and again, David proposes that you first scan the next 2 bytes after a supposed group+element. If they contain an upper-case character and this combination is one of the 31 VRs defined in the standard, then you probably deal with an explicit TS. If not, it's probably implicit. An extra check might be done on this assumption: if it's implicit, the 4 bytes after the group-element should contain the value length. Skip to the next group-element based on this value length and you should find another group-element. Check if the bytes correspond indeed to a group-element that is part of the dicom dictionary.

@ivmartel ivmartel modified the milestones: Future, 0.26.0 Nov 30, 2018
@ivmartel
Copy link
Owner Author

Ok, lets do it! Do you have a link to the Pixelmedcode?

@tguiot
Copy link

tguiot commented Nov 30, 2018

here: http://www.dclunie.com/pixelmed/software/20181018_current/index.html
you can find the function isDicomOrAcrNemaFile in class \com\pixelmed\dicom\DicomFileUtilities.java at line 74 which is the coded version of the strategy described above.

for guessing the transfer syntax you have to look at class \com\pixelmed\dicom\DicomInputStream.java, function initializeTransferSyntax and, probably more relevant, function guessTransferSyntaxToReadDataSet at line 142

The javascript version of isDicomOrAcrNemaFile would be called in if(magicword !== "DICM") and the guessTransferSyntaxToReadDataSet would be called in if (typeof this.dicomElements.x00020010 === "undefined")

@danielsnider
Copy link

Some DICOM data could not have the DICM preamble. I could be interesting to try and display it anyway...

+1 yes please! Try to display it!

@ivmartel
Copy link
Owner Author

ivmartel commented Apr 9, 2019

Careful with the pixelmed link, the folder names do change!

The root folder of the pixelmed code is dclunie.com/pixelmed/software (but maybe it changes to...).

@ivmartel
Copy link
Owner Author

ivmartel commented Apr 9, 2019

As a ref, here is the code of the isDicomOrAcrNemaFile method (at com\pixelmed\dicom\DicomFileUtilities.java#L94):

if (length >= 136 
  && new String(b,128,4).equals("DICM")
  && extractUnsigned16(b,132,false) == 0x0002
  /*&& extractUnsigned16(b,134,false) == 0x0000*/
) {
  // do NOT insist on group length (bad example dicomvl.imagAAAa0005r.dc3)
  success = true;
}
else if (length >= 136
  && new String(b,128,4).equals("DICM")
  && extractUnsigned16(b,132,true) == 0x0002
  /*&& extractUnsigned16(b,134,true) == 0x0000*/
) {
  // big endian metaheader is illegal but allow it (bad example dicomvl.fich1.dcm)
  success = true;
}
else if (length >= 8
  && extractUnsigned16(b,0,false) == 0x0008
  && extractUnsigned16(b,2,false) <= 0x0018 /* SOPInstanceUID */
  && (extractUnsigned32(b,4,false) <= 0x0100 /* sane VL */
  || (Character.isUpperCase((char)(b[4])) && Character.isUpperCase((char)(b[5]))) /* EVR */)
) {
    success = true;
}
else if (length >= 8
  && extractUnsigned16(b,0,true) == 0x0008
  && extractUnsigned16(b,2,true) <= 0x0018 /* SOPInstanceUID */
  && (extractUnsigned32(b,4,true) <= 0x0100 /* sane VL */
  || (Character.isUpperCase((char)(b[4])) && Character.isUpperCase((char)(b[5]))) /* EVR */)
) {
    success = true;
}

And the code of guessTransferSyntaxToReadDataSet (at com\pixelmed\dicom\DicomInputStream.java#L144):

boolean bigendian = false;
boolean explicitvr = false;
if (markSupported()) {
  mark(10);
  if (read(b,0,8) == 8) {
    // examine probable group number ... assume <= 0x00ff
    if (b[0] < b[1]) bigendian=true;
    else if (b[0] == 0 && b[1] == 0) {
      // blech ... group number is zero
      // no point in looking at element number
      // as it will probably be zero too (group length)
      // try the 32 bit value length of implicit vr
      if (b[4] < b[7]) bigendian=true;
    }
    // else little endian
    if (Character.isUpperCase((char)(b[4])) 
      && Character.isUpperCase((char)(b[5]))) explicitvr=true;
  }
  // go back to start of dataset
  reset();
}
// else can't guess or unrecognized
// ... assume default ImplicitVRLittleEndian (most common without metaheader due to Mallinckrodt CTN default)

if (bigendian)
  if (explicitvr)
    TransferSyntaxToReadDataSet = new TransferSyntax(TransferSyntax.ExplicitVRBigEndian);
  else
    throw new IOException("Not a DICOM file (masquerades as explicit VR big endian)");
else
  if (explicitvr)
    TransferSyntaxToReadDataSet = new TransferSyntax(TransferSyntax.ExplicitVRLittleEndian);
  else
    TransferSyntaxToReadDataSet = new TransferSyntax(TransferSyntax.ImplicitVRLittleEndian);

@ivmartel
Copy link
Owner Author

ivmartel commented Apr 9, 2019

Fixed with the merge of #625.

@ivmartel ivmartel closed this as completed Apr 9, 2019
neandrake pushed a commit to neandrake/dicom-pipe that referenced this issue May 19, 2020
fixes the `test_no_preamble_start_with_0005` tests, referenced ivmartel/dwv#188 (comment)
neandrake added a commit to neandrake/dicom-pipe that referenced this issue May 19, 2020
fixes the `test_no_preamble_start_with_0005` tests, referenced ivmartel/dwv#188 (comment)
neandrake added a commit to neandrake/dicom-pipe that referenced this issue Apr 29, 2024
fixes the `test_no_preamble_start_with_0005` tests, referenced ivmartel/dwv#188 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants