/// <summary> /// Run the decompressor. /// </summary> /// <param name="file"></param> public void Process(ClearCanvas.Dicom.DicomFile file) { var proposedTs = ClearCanvas.Dicom.TransferSyntax.GetTransferSyntax(OutputTransferSyntax); var currentTs = file.TransferSyntax; ClearCanvas.Dicom.TransferSyntax finalTs = currentTs; if (proposedTs != TransferSyntax.ExplicitVrBigEndian && proposedTs != TransferSyntax.ImplicitVrLittleEndian && proposedTs != TransferSyntax.ExplicitVrLittleEndian) { log.Warn("Decompressor cannot supports target transfer syntax of EVBE, IVLE, EVLE only. Using IVLE .."); finalTs = TransferSyntax.ImplicitVrLittleEndian; } else { finalTs = proposedTs; } log.Info(string.Format("Deompress: Proposed: {0}, current {1}, final {2}", proposedTs, currentTs, finalTs)); if (currentTs != finalTs) { file.ChangeTransferSyntax(finalTs); } }
protected override bool Initialize(Model.WorkQueue item, out string failureDescription) { if (!base.Initialize(item, out failureDescription)) return false; XmlElement element = WorkQueueItem.Data.DocumentElement; string syntax = element.Attributes["syntax"].Value; CompressTransferSyntax = TransferSyntax.GetTransferSyntax(syntax); return true; }
private IAction CreateAction(TransferSyntax syntax, IResourceResolver resolver) { var action = new ClickAction(syntax.UidString, new ActionPath("dicomstudybrowser-contextmenu/Change Transfer Syntax/" + syntax.ToString(), resolver), ClickActionFlags.None, resolver) {Enabled = Enabled}; this.EnabledChanged += (sender, args) => action.Enabled = Enabled; action.SetClickHandler(() => ChangeToSyntax(syntax)); action.Label = syntax.ToString(); return action; }
/// <summary> /// Constructor. /// </summary> /// <param name="serverPartitionKey">The <see cref="ServerPartition"/> the study belongs to.</param> /// <param name="studyInstanceUid">The Study</param> /// <param name="folder">The folder (typically the study date) where the study is stored.</param> /// <param name="filesystemKey">The filesystem the study is stored on.</param> /// <param name="transferSyntax">The <see cref="TransferSyntax"/> of the study.</param> public InsertFilesystemStudyStorageCommand(ServerEntityKey serverPartitionKey, string studyInstanceUid, string folder, ServerEntityKey filesystemKey, TransferSyntax transferSyntax) : base("Insert FilesystemStudyStorage") { _serverPartitionKey = serverPartitionKey; _studyInstanceUid = studyInstanceUid; _folder = folder; _filesystemKey = filesystemKey; _transfersyntax = transferSyntax; }
/// <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; }
public void ChangeToSyntax(TransferSyntax syntax) { _syntax = syntax; BackgroundTask task = null; try { task = new BackgroundTask(ChangeToSyntax, false, Context.SelectedStudy); ProgressDialog.Show(task, this.Context.DesktopWindow, true); } catch(Exception e) { Platform.Log(LogLevel.Error, e); string message = String.Format("An error occurred while compressing; folder must be deleted manually: {0}", _tempPath); this.Context.DesktopWindow.ShowMessageBox(message, MessageBoxActions.Ok); } finally { _tempPath = null; if (task != null) task.Dispose(); } }
/// <summary> /// Gets the <see cref="TransferSyntax"/>es of the available <see cref="IDicomCodecFactory"/> implementations. /// </summary> public static TransferSyntax[] GetCodecTransferSyntaxes() { TransferSyntax[] syntaxes = new TransferSyntax[_dictionary.Count]; _dictionary.Keys.CopyTo(syntaxes, 0); return syntaxes; }
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; }
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."); DicomUncompressedPixelData pd = new DicomUncompressedPixelData(DataSet); DicomCompressedPixelData fragments = new DicomCompressedPixelData(pd); // Set before compression, the codecs need it. fragments.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."); DicomCompressedPixelData fragments = new DicomCompressedPixelData(DataSet); DicomUncompressedPixelData pd = new DicomUncompressedPixelData(fragments); codec.Decode(fragments, pd, parameters); pd.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; } } }
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> /// Updates the status of a study to a new status /// </summary> protected virtual void UpdateStudyStatus(StudyStorageLocation theStudyStorage, StudyStatusEnum theStatus, TransferSyntax theSyntax) { DBUpdateTime.Add( delegate { using ( IUpdateContext updateContext = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush)) { // Select the Server Transfer Syntax ServerTransferSyntaxSelectCriteria syntaxCriteria = new ServerTransferSyntaxSelectCriteria(); IServerTransferSyntaxEntityBroker syntaxBroker = updateContext.GetBroker<IServerTransferSyntaxEntityBroker>(); syntaxCriteria.Uid.EqualTo(theSyntax.UidString); ServerTransferSyntax serverSyntax = syntaxBroker.FindOne(syntaxCriteria); if (serverSyntax == null) { Platform.Log(LogLevel.Error, "Unable to load ServerTransferSyntax for {0}. Unable to update study status.", theSyntax.Name); return; } // Get the FilesystemStudyStorage update broker ready IFilesystemStudyStorageEntityBroker filesystemQueueBroker = updateContext.GetBroker<IFilesystemStudyStorageEntityBroker>(); FilesystemStudyStorageUpdateColumns filesystemQueueUpdate = new FilesystemStudyStorageUpdateColumns { ServerTransferSyntaxKey = serverSyntax.GetKey() }; FilesystemStudyStorageSelectCriteria filesystemQueueCriteria = new FilesystemStudyStorageSelectCriteria(); filesystemQueueCriteria.StudyStorageKey.EqualTo(theStudyStorage.GetKey()); // Get the StudyStorage update broker ready IStudyStorageEntityBroker studyStorageBroker = updateContext.GetBroker<IStudyStorageEntityBroker>(); StudyStorageUpdateColumns studyStorageUpdate = new StudyStorageUpdateColumns { StudyStatusEnum = theStatus, LastAccessedTime = Platform.Time }; if (!filesystemQueueBroker.Update(filesystemQueueCriteria,filesystemQueueUpdate)) { Platform.Log(LogLevel.Error, "Unable to update FilesystemQueue row: Study {0}, Server Entity {1}", theStudyStorage.StudyInstanceUid, theStudyStorage.ServerPartitionKey); } else if (!studyStorageBroker.Update(theStudyStorage.GetKey(),studyStorageUpdate)) { Platform.Log(LogLevel.Error, "Unable to update StudyStorage row: Study {0}, Server Entity {1}", theStudyStorage.StudyInstanceUid, theStudyStorage.ServerPartitionKey); } else updateContext.Commit(); } } ); }
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."); } DicomUncompressedPixelData pd = new DicomUncompressedPixelData(DataSet); DicomCompressedPixelData fragments = new DicomCompressedPixelData(pd); // Set before compression, the codecs need it. fragments.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."); } DicomCompressedPixelData fragments = new DicomCompressedPixelData(DataSet); DicomUncompressedPixelData pd = new DicomUncompressedPixelData(fragments); codec.Decode(fragments, pd, parameters); pd.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; } } }
internal override ByteBuffer GetByteBuffer(TransferSyntax syntax, String specificCharacterSet) { throw new DicomException("Unexpected call to GetByteBuffer() for a SQ attribute"); }
internal abstract ByteBuffer GetByteBuffer(TransferSyntax syntax, String specificCharacterSet);
/// <summary> /// Do the restore. /// </summary> /// <param name="queueItem">The queue item to restore.</param> public void Run(RestoreQueue queueItem) { using (var context = new RestoreProcessorContext(queueItem)) { try { // Load up related classes. using (IReadContext readContext = _hsmArchive.PersistentStore.OpenReadContext()) { _archiveStudyStorage = ArchiveStudyStorage.Load(readContext, queueItem.ArchiveStudyStorageKey); _serverSyntax = ServerTransferSyntax.Load(readContext, _archiveStudyStorage.ServerTransferSyntaxKey); _syntax = TransferSyntax.GetTransferSyntax(_serverSyntax.Uid); var parms = new StudyStorageLocationQueryParameters {StudyStorageKey = queueItem.StudyStorageKey}; var broker = readContext.GetBroker<IQueryStudyStorageLocation>(); _location = broker.FindOne(parms); if (_location == null) { _studyStorage = StudyStorage.Load(readContext, queueItem.StudyStorageKey); if (_studyStorage==null) { DateTime scheduleTime = Platform.Time.AddMinutes(5); Platform.Log(LogLevel.Error, "Unable to find storage location, rescheduling restore request to {0}", scheduleTime); queueItem.FailureDescription = "Unable to find storage location, rescheduling request."; _hsmArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Pending, scheduleTime); return; } } } if (_location == null) { Platform.Log(LogLevel.Info, "Starting restore of nearline study: {0}", _studyStorage.StudyInstanceUid); // Get the zip file path from the xml data in the ArchiveStudyStorage entry // Also store the "StudyFolder" for use below string studyFolder; string zipFile = GetZipFileName(out studyFolder); // Do a test read of the zip file. If it succeeds, the file is available, if it // fails, we just set back to pending and recheck. if (!CanReadZip(zipFile, queueItem)) return; RestoreNearlineStudy(queueItem, zipFile, studyFolder); } else { Platform.Log(LogLevel.Info, "Starting restore of online study: {0}", _location.StudyInstanceUid); // Get the zip file path from the xml data in the ArchiveStudyStorage entry // Also store the "StudyFolder" for use below string studyFolder; string zipFile = GetZipFileName(out studyFolder); // Do a test read of the zip file. If it succeeds, the file is available, if it // fails, we just set back to pending and recheck. if (!CanReadZip(zipFile, queueItem)) return; RestoreOnlineStudy(queueItem, zipFile, _location.GetStudyPath()); } } catch (Exception e) { Platform.Log(LogLevel.Error, e, "Unexpected exception processing restore request for {0} on archive {1}", _studyStorage == null ? (_location == null ? string.Empty : _location.StudyInstanceUid) : _studyStorage.StudyInstanceUid, _hsmArchive.PartitionArchive.Description); queueItem.FailureDescription = e.Message; _hsmArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time); } } }
/// <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> /// 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 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 } length += 4 + 4; // offset tag if (Flags.IsSet(options, DicomWriteOptions.WriteFragmentOffsetTable) && _table != null) length += (uint)(_table.Count * 4); foreach (DicomFragment fragment in this._fragments) { length += 4; // item tag length += 4; // fragment length length += fragment.Length; } return length; }
internal override ByteBuffer GetByteBuffer(TransferSyntax syntax, string specificCharacterSet) { throw new NotImplementedException(); }
/// <summary> /// Constructor. /// </summary> /// <param name="message"></param> protected DicomPixelData(DicomMessageBase message) : this(message.DataSet) { _transferSyntax = message.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); var rawPixelData = (byte[])pixelData.Values; //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(rawPixelData, 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(rawPixelData, 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; } } }
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; //if (_value == null) //{ // return bb; // return empty buffer if the value is not set //} bb.SetString(_value, (byte) ' '); return bb; }
public void ChangeTransferSyntax(TransferSyntax newTransferSyntax) { ChangeTransferSyntax(newTransferSyntax, null, null); }
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; } } }
/// <summary> /// Get default parameters for the codec. /// </summary> /// <param name="syntax">The transfer syntax to get the parameters for.</param> /// <param name="collection">The <see cref="DicomAttributeCollection"/> that the codec will work on.</param> /// <returns>null if no codec is registered, the parameters otherwise.</returns> public static DicomCodecParameters GetCodecParameters(TransferSyntax syntax, DicomAttributeCollection collection) { IDicomCodecFactory factory; if (!_dictionary.TryGetValue(syntax, out factory)) return null; return factory.GetCodecParameters(collection); }
/// <summary> /// Do the restore. /// </summary> /// <param name="queueItem">The queue item to restore.</param> public void Run(RestoreQueue queueItem) { using (RestoreProcessorContext context = new RestoreProcessorContext(queueItem)) { try { // Load up related classes. using (IReadContext readContext = _nasArchive.PersistentStore.OpenReadContext()) { _archiveStudyStorage = ArchiveStudyStorage.Load(readContext, queueItem.ArchiveStudyStorageKey); _serverSyntax = ServerTransferSyntax.Load(readContext, _archiveStudyStorage.ServerTransferSyntaxKey); _syntax = TransferSyntax.GetTransferSyntax(_serverSyntax.Uid); StudyStorageLocationQueryParameters parms = new StudyStorageLocationQueryParameters {StudyStorageKey = queueItem.StudyStorageKey}; IQueryStudyStorageLocation broker = readContext.GetBroker<IQueryStudyStorageLocation>(); _location = broker.FindOne(parms); if (_location == null) { _studyStorage = StudyStorage.Load(readContext, queueItem.StudyStorageKey); if (_studyStorage==null) { DateTime scheduleTime = Platform.Time.AddMinutes(5); Platform.Log(LogLevel.Error, "Unable to find storage location, rescheduling restore request to {0}", scheduleTime); queueItem.FailureDescription = "Unable to find storage location, rescheduling request."; _nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Pending, scheduleTime); return; } } } if (_location == null) Platform.Log(LogLevel.Info, "Starting restore of nearline study: {0}", _studyStorage.StudyInstanceUid); else Platform.Log(LogLevel.Info, "Starting restore of online study: {0}", _location.StudyInstanceUid); // If restoring a Nearline study, select a filesystem string destinationFolder; if (_location == null) { ServerFilesystemInfo fs = _nasArchive.Selector.SelectFilesystem(); if (fs == null) { DateTime scheduleTime = Platform.Time.AddMinutes(5); Platform.Log(LogLevel.Error, "No writeable filesystem for restore, rescheduling restore request to {0}", scheduleTime); queueItem.FailureDescription = "No writeable filesystem for restore, rescheduling request."; _nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Pending, scheduleTime); return; } destinationFolder = Path.Combine(fs.Filesystem.FilesystemPath, _nasArchive.ServerPartition.PartitionFolder); } else destinationFolder = _location.GetStudyPath(); // Get the zip file path from the xml data in the ArchiveStudyStorage entry // Also store the "StudyFolder" for use below string studyFolder = String.Empty; string filename = String.Empty; string studyInstanceUid = String.Empty; XmlElement element = _archiveStudyStorage.ArchiveXml.DocumentElement; if (element!=null) foreach (XmlElement node in element.ChildNodes) if (node.Name.Equals("StudyFolder")) studyFolder = node.InnerText; else if (node.Name.Equals("Filename")) filename = node.InnerText; else if (node.Name.Equals("Uid")) studyInstanceUid = node.InnerText; string zipFile = Path.Combine(_nasArchive.NasPath, studyFolder); zipFile = Path.Combine(zipFile, studyInstanceUid); zipFile = Path.Combine(zipFile, filename); // Do a test read of the zip file. If it succeeds, the file is available, if it // fails, we just set back to pending and recheck. try { FileStream stream = File.OpenRead(zipFile); // Read a byte, just in case that makes a difference. stream.ReadByte(); stream.Close(); stream.Dispose(); } catch (Exception ex) { DateTime scheduledTime = Platform.Time.AddSeconds(NasSettings.Default.ReadFailRescheduleDelaySeconds); Platform.Log(LogLevel.Error, ex, "Archive {0} for Study {1} is unreadable, rescheduling restore to {2}", zipFile, _studyStorage == null ? (_location == null ? string.Empty : _location.StudyInstanceUid) : _studyStorage.StudyInstanceUid, scheduledTime); // Just reschedule in "Restoring" state, the file is unreadable. _nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Restoring, scheduledTime); return; } if (_location == null) RestoreNearlineStudy(queueItem, zipFile, destinationFolder, studyFolder); else RestoreOnlineStudy(queueItem, zipFile, destinationFolder); } catch (Exception e) { Platform.Log(LogLevel.Error, e, "Unexpected exception processing restore request for {0} on archive {1}", _studyStorage == null ? (_location == null ? string.Empty : _location.StudyInstanceUid) : _studyStorage.StudyInstanceUid, _nasArchive.PartitionArchive.Description); queueItem.FailureDescription = e.Message; _nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time); } } }
/// <summary> /// Get a codec instance from the registry. /// </summary> /// <param name="syntax">The transfer syntax to get a codec for.</param> /// <returns>null if a codec has not been registered, an <see cref="IDicomCodec"/> instance otherwise.</returns> public static IDicomCodec GetCodec(TransferSyntax syntax) { IDicomCodecFactory factory; if (!_dictionary.TryGetValue(syntax, out factory)) return null; return factory.GetDicomCodec(); }
/// <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 }
/// <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); }
/// <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> /// Get a <see cref="ByteBuffer"/> for the frame's data. /// </summary> /// <returns></returns> public ByteBuffer GetByteBuffer(TransferSyntax syntax) { if (_reference != null) return Load(); // no need to swap, always OB return new ByteBuffer(GetByteArray(), ByteBuffer.LocalMachineEndian); }
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 } // write the offset table (item tag is always present, though content may be zero length) length += 4 + 4; // item tag and length if (Flags.IsSet(options, DicomWriteOptions.WriteFragmentOffsetTable) && _table != null) length += (uint) (_table.Count*4); foreach (DicomFragment fragment in this._fragments) { length += 4; // item tag length += 4; // fragment length length += fragment.Length; // no Item Delimitation Item (fragments are always explicit length) } length += 4 + 4; // Sequence Delimitation Item (fragment sequences are always undefined length) return length; }
/// <summary> /// Process the rule /// </summary> /// <param name="file"></param> public void Process(ClearCanvas.Dicom.DicomFile file) { var proposedTs = ClearCanvas.Dicom.TransferSyntax.GetTransferSyntax(OutputTransferSyntax); var currentTs = file.TransferSyntax; var bitsStored = file.DataSet[DicomTags.BitsStored].GetInt16(0, 0); var bitsAllocated = file.DataSet[DicomTags.BitsAllocated].GetInt16(0, 0); var samplesPerPixel = file.DataSet[DicomTags.SamplesPerPixel].GetInt16(0, 0); var photometricInterpretation = file.DataSet[DicomTags.PhotometricInterpretation].GetString(0, ""); log.Info(string.Format( "compress: bits stored {0}, bits allocated {1}, samples per pixel {2}, photometric {3}", bitsStored, bitsAllocated, samplesPerPixel, photometricInterpretation)); log.Info(string.Format("Compress: Proposed: {0}, current {1}", proposedTs, currentTs)); log.Info("Checking that proposed transfer syntax is consistent with the dataset"); ClearCanvas.Dicom.TransferSyntax finalTs = currentTs; try { if (proposedTs == TransferSyntax.JpegBaselineProcess1) { ValidateJPEGBaselineProcess1(bitsAllocated, bitsStored, samplesPerPixel, photometricInterpretation); } else if (proposedTs == TransferSyntax.JpegExtendedProcess24) { ValidateJPEGExtendedProcess2And4(bitsAllocated, bitsStored, samplesPerPixel, photometricInterpretation); } else if (proposedTs == TransferSyntax.JpegLosslessNonHierarchicalFirstOrderPredictionProcess14SelectionValue1) { ValidateJpegLosslessNonHierarchicalFirstOrderPredictionProcess14SelectionValue1(bitsAllocated, bitsStored, samplesPerPixel, photometricInterpretation); } else if (proposedTs == TransferSyntax.Jpeg2000ImageCompression) { ValidateJpeg2000Lossy(bitsAllocated, bitsStored, samplesPerPixel, photometricInterpretation); } else if (proposedTs == TransferSyntax.Jpeg2000ImageCompressionLosslessOnly) { ValidateJpeg2000Lossless(bitsAllocated, bitsStored, samplesPerPixel, photometricInterpretation); } // Compression from non-compressed transfer syntaxes if (currentTs == TransferSyntax.ImplicitVrLittleEndian || currentTs == TransferSyntax.ExplicitVrLittleEndian || currentTs == TransferSyntax.ExplicitVrBigEndian) { // This is fine ... we're compressing something that isn't compressed. finalTs = proposedTs; } else { // Potentially a problem. We could be moving from a compressed syntax to // another compress syntax. We know the target syntax is legal for this dataset // but the toolkit pukes when moving encapsulated frames. // TO DO: More work needed here. finalTs = proposedTs; } log.Info(string.Format("Final ts {0}", finalTs)); } catch (NotSupportedException nse) { log.Error("Compression would be illegal and will NOT be applied. " + nse.ToString()); } if (currentTs != finalTs) { file.ChangeTransferSyntax(finalTs); } }