/// <summary> /// Calculate the length to write the attribute. /// </summary> /// <param name="syntax">The transfer syntax to calculate the length for.</param> /// <param name="options">The write options to calculate the length for.</param> /// <returns></returns> internal virtual uint CalculateWriteLength(TransferSyntax syntax, DicomWriteOptions options) { uint length = 4; // element tag if (syntax.ExplicitVr) { length += 2; // vr if (Tag.VR.Is16BitLengthField) length += 2; else length += 6; } else { length += 4; // length tag } length += StreamLength; if ((length & 0x00000001) != 0) length++; return length; }
/// <summary> /// Constructor. /// </summary> /// <param name="message"></param> protected DicomPixelData(DicomMessageBase message) : this(message.DataSet) { _transferSyntax = message.TransferSyntax; }
internal override uint CalculateWriteLength(TransferSyntax syntax, DicomWriteOptions options) { uint length = 0; length += 4; // element tag if (syntax.ExplicitVr) { length += 2; // vr length += 6; // length } else { length += 4; // length } if (_values != null) { foreach (DicomSequenceItem item in _values) { length += 4 + 4; // Sequence Item Tag length += item.CalculateWriteLength(syntax, options & ~DicomWriteOptions.CalculateGroupLengths); if (!Flags.IsSet(options, DicomWriteOptions.ExplicitLengthSequenceItem)) length += 4 + 4; // Sequence Item Delimitation Item } if (!Flags.IsSet(options, DicomWriteOptions.ExplicitLengthSequence)) length += 4 + 4; // Sequence Delimitation Item } return length; }
internal override ByteBuffer GetByteBuffer(TransferSyntax syntax, String specificCharacterSet) { throw new DicomException("Unexpected call to GetByteBuffer() for a SQ attribute"); }
internal override ByteBuffer GetByteBuffer(TransferSyntax syntax, String specificCharacterSet) { ByteBuffer bb = new ByteBuffer(syntax.Endian); if (Tag.VR.SpecificCharacterSet) bb.SpecificCharacterSet = specificCharacterSet; //if (_value == null) //{ // return bb; // return empty buffer if the value is not set //} bb.SetString(_value, (byte)' '); return bb; }
/// <summary> /// Get the string representation of the value /// when the attribute is saved using the specific character set and transfer syntax /// and read again using one of the GetString methods /// </summary> /// <param name="syntax"></param> /// <param name="specificCharacterSet"></param> /// <returns></returns> public virtual string GetEncodedString(TransferSyntax syntax, String specificCharacterSet) { var buffer = GetByteBuffer(syntax, specificCharacterSet); if (buffer == null) return null; return buffer.GetString(); }
internal abstract ByteBuffer GetByteBuffer(TransferSyntax syntax, String specificCharacterSet);
/// <summary> /// Creates a new DicomMessage instance from an existing <see cref="DicomFile"/>. /// </summary> /// <remarks> /// This method creates a new command set for the DicomMessage, but shares the DataSet with <paramref name="file"/>. /// </remarks> /// <param name="file">The <see cref="DicomFile"/> to change into a DicomMessage.</param> public DicomMessage(DicomFile file) { _transferSyntax = file.TransferSyntax; MetaInfo = new DicomAttributeCollection(0x00000000,0x0000FFFF); DataSet = file.DataSet; }
/// <summary> /// Finds the next directory record of the specified <paramref name="recordType"/>, starting at the specified <paramref name="startIndex"/> /// </summary> /// <param name="recordType">Type of the record.</param> /// <param name="startIndex">The start index.</param> /// <returns></returns> private void CalculateOffsets(TransferSyntax syntax, DicomWriteOptions options) { foreach (DicomSequenceItem sq in (DicomSequenceItem[])_dicomDirFile.DataSet[DicomTags.DirectoryRecordSequence].Values) { DirectoryRecordSequenceItem record = sq as DirectoryRecordSequenceItem; if (record == null) throw new ApplicationException("Unexpected type for directory record: " + sq.GetType()); record.Offset = _fileOffset; _fileOffset += 4 + 4; // Sequence Item Tag _fileOffset += record.CalculateWriteLength(syntax, options & ~DicomWriteOptions.CalculateGroupLengths); if (!Flags.IsSet(options, DicomWriteOptions.ExplicitLengthSequenceItem)) _fileOffset += 4 + 4; // Sequence Item Delimitation Item } if (!Flags.IsSet(options, DicomWriteOptions.ExplicitLengthSequence)) _fileOffset += 4 + 4; // Sequence Delimitation Item }
internal override ByteBuffer GetByteBuffer(TransferSyntax syntax, string specificCharacterSet) { ByteBuffer bb = new ByteBuffer(syntax.Endian); bb.SetString(ToString(), 0x00); return bb; }
internal override ByteBuffer GetByteBuffer(TransferSyntax syntax, string specificCharacterSet) { ByteBuffer bb = new ByteBuffer(syntax.Endian); if (Tag.VR.SpecificCharacterSet) bb.SpecificCharacterSet = specificCharacterSet; bb.SetString(ToString(), (byte)' '); return bb; }
/// <summary> /// Unregisters a private transfer syntax. /// </summary> /// <param name="transferSyntax">The private transfer syntax to unreigster.</param> public static void UnregisterTransferSyntax(TransferSyntax transferSyntax) { Platform.CheckForNullReference(transferSyntax, "transferSyntax"); _privateTransferSyntaxes.Remove(transferSyntax.UidString); }
/// <summary> /// Registers a private transfer syntax. /// </summary> /// <param name="transferSyntax">The private transfer syntax to reigster.</param> public static void RegisterTransferSyntax(TransferSyntax transferSyntax) { Platform.CheckForNullReference(transferSyntax, "transferSyntax"); Platform.CheckTrue(!_transferSyntaxes.ContainsKey(transferSyntax.UidString), "Cannot redefine a standard transfer syntax."); Platform.CheckTrue(!_privateTransferSyntaxes.ContainsKey(transferSyntax.UidString), "The specified private transfer syntax UID is already defined."); _privateTransferSyntaxes.Add(transferSyntax.UidString, transferSyntax); }
public void ChangeTransferSyntax(TransferSyntax newTransferSyntax, IDicomCodec inputCodec, DicomCodecParameters inputParameters) { IDicomCodec codec = inputCodec; DicomCodecParameters parameters = inputParameters; if (newTransferSyntax.Encapsulated && TransferSyntax.Encapsulated) throw new DicomCodecException("Source and destination transfer syntaxes encapsulated"); if (newTransferSyntax.Encapsulated) { if (codec == null) { codec = DicomCodecRegistry.GetCodec(newTransferSyntax); if (codec == null) { Platform.Log(LogLevel.Error, "Unable to get registered codec for {0}", newTransferSyntax); throw new DicomCodecException("No registered codec for: " + newTransferSyntax.Name); } } if (parameters == null) parameters = DicomCodecRegistry.GetCodecParameters(newTransferSyntax, DataSet); DicomAttribute pixelData; if (DataSet.TryGetAttribute(DicomTags.PixelData, out pixelData)) { if (pixelData.IsNull) throw new DicomCodecException("Sop pixel data has no valid value and cannot be compressed."); new OverlayPlaneModuleIod(DataSet).ExtractEmbeddedOverlays(); var pd = new DicomUncompressedPixelData(DataSet); using (var pixelStream = ((DicomAttributeBinary) pixelData).AsStream()) { //Before compression, make the pixel data more "typical", so it's harder to mess up the codecs. //NOTE: Could combine mask and align into one method so we're not iterating twice, but I prefer having the methods separate. if (DicomUncompressedPixelData.RightAlign(pixelStream, pd.BitsAllocated, pd.BitsStored, pd.HighBit)) { var newHighBit = (ushort) (pd.HighBit - pd.LowBit); Platform.Log(LogLevel.Debug, "Right aligned pixel data (High Bit: {0}->{1}).", pd.HighBit, newHighBit); pd.HighBit = newHighBit; //correct high bit after right-aligning. DataSet[DicomTags.HighBit].SetUInt16(0, newHighBit); } if (DicomUncompressedPixelData.ZeroUnusedBits(pixelStream, pd.BitsAllocated, pd.BitsStored, pd.HighBit)) { Platform.Log(LogLevel.Debug, "Zeroed some unused bits before compression."); } } // Set transfer syntax before compression, the codecs need it. var fragments = new DicomCompressedPixelData(pd) { TransferSyntax = newTransferSyntax }; codec.Encode(pd, fragments, parameters); fragments.UpdateMessage(this); //TODO: should we validate the number of frames in the compressed data? if (!DataSet.TryGetAttribute(DicomTags.PixelData, out pixelData) || pixelData.IsNull) throw new DicomCodecException("Sop has no pixel data after compression."); } else { //A bit cheap, but check for basic image attributes - if any exist // and are non-empty, there should probably be pixel data too. DicomAttribute attribute; if (DataSet.TryGetAttribute(DicomTags.Rows, out attribute) && !attribute.IsNull) throw new DicomCodecException("Suspect Sop appears to be an image (Rows is non-empty), but has no pixel data."); if (DataSet.TryGetAttribute(DicomTags.Columns, out attribute) && !attribute.IsNull) throw new DicomCodecException("Suspect Sop appears to be an image (Columns is non-empty), but has no pixel data."); TransferSyntax = newTransferSyntax; } } else { if (codec == null) { codec = DicomCodecRegistry.GetCodec(TransferSyntax); if (codec == null) { Platform.Log(LogLevel.Error, "Unable to get registered codec for {0}", TransferSyntax); throw new DicomCodecException("No registered codec for: " + TransferSyntax.Name); } if (parameters == null) parameters = DicomCodecRegistry.GetCodecParameters(TransferSyntax, DataSet); } DicomAttribute pixelData; if (DataSet.TryGetAttribute(DicomTags.PixelData, out pixelData)) { if (pixelData.IsNull) throw new DicomCodecException("Sop pixel data has no valid value and cannot be decompressed."); var fragments = new DicomCompressedPixelData(DataSet); var pd = new DicomUncompressedPixelData(fragments); codec.Decode(fragments, pd, parameters); pd.TransferSyntax = TransferSyntax.ExplicitVrLittleEndian; TransferSyntax = TransferSyntax.ExplicitVrLittleEndian; pd.UpdateMessage(this); //TODO: should we validate the number of frames in the decompressed data? if (!DataSet.TryGetAttribute(DicomTags.PixelData, out pixelData) || pixelData.IsNull) throw new DicomCodecException("Sop has no pixel data after decompression."); } else { //NOTE: doing this for consistency, really. DicomAttribute attribute; if (DataSet.TryGetAttribute(DicomTags.Rows, out attribute) && !attribute.IsNull) throw new DicomCodecException("Suspect Sop appears to be an image (Rows is non-empty), but has no pixel data."); if (DataSet.TryGetAttribute(DicomTags.Columns, out attribute) && !attribute.IsNull) throw new DicomCodecException("Suspect Sop appears to be an image (Columns is non-empty), but has no pixel data."); TransferSyntax = TransferSyntax.ExplicitVrLittleEndian; } } }
public void ChangeTransferSyntax(TransferSyntax newTransferSyntax) { ChangeTransferSyntax(newTransferSyntax, null, null); }
public DicomWriteStatus Write(TransferSyntax syntax, DicomAttributeCollection dataset, DicomWriteOptions options) { TransferSyntax = syntax; foreach (DicomAttribute item in dataset) { if (item.Tag.Element == 0x0000) continue; if (item.IsEmpty) continue; if (Flags.IsSet(options, DicomWriteOptions.CalculateGroupLengths) && item.Tag.Group != _group && item.Tag.Group <= 0x7fe0) { _group = item.Tag.Group; _writer.Write((ushort)_group); _writer.Write((ushort)0x0000); if (_syntax.ExplicitVr) { _writer.Write((byte)'U'); _writer.Write((byte)'L'); _writer.Write((ushort)4); } else { _writer.Write((uint)4); } _writer.Write((uint)dataset.CalculateGroupWriteLength(_group, _syntax, options)); } _writer.Write((ushort)item.Tag.Group); _writer.Write((ushort)item.Tag.Element); if (_syntax.ExplicitVr) { _writer.Write((byte)item.Tag.VR.Name[0]); _writer.Write((byte)item.Tag.VR.Name[1]); } if (item is DicomAttributeSQ) { DicomAttributeSQ sq = item as DicomAttributeSQ; if (_syntax.ExplicitVr) _writer.Write((ushort)0x0000); if (Flags.IsSet(options, DicomWriteOptions.ExplicitLengthSequence)) { int hl = _syntax.ExplicitVr ? 12 : 8; _writer.Write((uint)sq.CalculateWriteLength(_syntax, options & ~DicomWriteOptions.CalculateGroupLengths) - (uint)hl); } else { _writer.Write((uint)UndefinedLength); } foreach (DicomSequenceItem ids in item.Values as DicomSequenceItem[]) { _writer.Write((ushort)DicomTag.Item.Group); _writer.Write((ushort)DicomTag.Item.Element); if (Flags.IsSet(options, DicomWriteOptions.ExplicitLengthSequenceItem)) { _writer.Write((uint)ids.CalculateWriteLength(_syntax, options & ~DicomWriteOptions.CalculateGroupLengths)); } else { _writer.Write((uint)UndefinedLength); } Write(this.TransferSyntax, ids, options & ~DicomWriteOptions.CalculateGroupLengths); if (!Flags.IsSet(options, DicomWriteOptions.ExplicitLengthSequenceItem)) { _writer.Write((ushort)DicomTag.ItemDelimitationItem.Group); _writer.Write((ushort)DicomTag.ItemDelimitationItem.Element); _writer.Write((uint)0x00000000); } } if (!Flags.IsSet(options, DicomWriteOptions.ExplicitLengthSequence)) { _writer.Write((ushort)DicomTag.SequenceDelimitationItem.Group); _writer.Write((ushort)DicomTag.SequenceDelimitationItem.Element); _writer.Write((uint)0x00000000); } } else if (item is DicomFragmentSequence) { DicomFragmentSequence fs = item as DicomFragmentSequence; if (_syntax.ExplicitVr) _writer.Write((ushort)0x0000); _writer.Write((uint)UndefinedLength); _writer.Write((ushort)DicomTag.Item.Group); _writer.Write((ushort)DicomTag.Item.Element); if (Flags.IsSet(options, DicomWriteOptions.WriteFragmentOffsetTable) && fs.HasOffsetTable) { _writer.Write((uint)fs.OffsetTableBuffer.Length); fs.OffsetTableBuffer.CopyTo(_writer); } else { _writer.Write((uint)0x00000000); } foreach (DicomFragment bb in fs.Fragments) { _writer.Write((ushort)DicomTag.Item.Group); _writer.Write((ushort)DicomTag.Item.Element); _writer.Write((uint)bb.Length); bb.GetByteBuffer(_syntax).CopyTo(_writer); } _writer.Write((ushort)DicomTag.SequenceDelimitationItem.Group); _writer.Write((ushort)DicomTag.SequenceDelimitationItem.Element); _writer.Write((uint)0x00000000); } else { DicomAttribute de = item; ByteBuffer theData = de.GetByteBuffer(_syntax, dataset.SpecificCharacterSet); if (_syntax.ExplicitVr) { if (de.Tag.VR.Is16BitLengthField) { _writer.Write((ushort)theData.Length); } else { _writer.Write((ushort)0x0000); _writer.Write((uint)theData.Length); } } else { _writer.Write((uint)theData.Length); } if (theData.Length > 0) theData.CopyTo(_writer); } } return DicomWriteStatus.Success; }