Example #1
0
        public static DicomFile Open(Stream stream, Encoding fallbackEncoding)
        {
            if (fallbackEncoding == null)
            {
                throw new ArgumentNullException("fallbackEncoding");
            }
            var df = new DicomFile();

            try {
                var source = new StreamByteSource(stream);

                var reader = new DicomFileReader();
                reader.Read(source,
                            new DicomDatasetReaderObserver(df.FileMetaInfo),
                            new DicomDatasetReaderObserver(df.Dataset, fallbackEncoding));

                df.Format = reader.FileFormat;

                df.Dataset.InternalTransferSyntax = reader.Syntax;

                return(df);
            } catch (Exception e) {
                throw new DicomFileException(df, e.Message, e);
            }
        }
Example #2
0
        /// <summary>
        /// Asynchronously read DICOM Directory from stream.
        /// </summary>
        /// <param name="stream">Stream to read.</param>
        /// <param name="fallbackEncoding">Encoding to apply if it cannot be identified from DICOM directory.</param>
        /// <param name="stop">Stop criterion in dataset.</param>
        /// <returns>Awaitable <see cref="DicomDirectory"/> instance.</returns>
        public static new async Task <DicomDirectory> OpenAsync(Stream stream, Encoding fallbackEncoding, Func <ParseState, bool> stop = null)
        {
            if (fallbackEncoding == null)
            {
                throw new ArgumentNullException(nameof(fallbackEncoding));
            }
            var df = new DicomDirectory();

            try
            {
                var source = new StreamByteSource(stream);

                var reader      = new DicomFileReader();
                var dirObserver = new DicomDirectoryReaderObserver(df.Dataset);

                var result =
                    await
                    reader.ReadAsync(
                        source,
                        new DicomDatasetReaderObserver(df.FileMetaInfo),
                        new DicomReaderMultiObserver(
                            new DicomDatasetReaderObserver(df.Dataset, fallbackEncoding),
                            dirObserver),
                        stop).ConfigureAwait(false);

                return(FinalizeDicomDirectoryLoad(df, reader, dirObserver, result));
            }
            catch (Exception e)
            {
                throw new DicomFileException(df, e.Message, e);
            }
        }
Example #3
0
        public void Read_ValidExplicitVRSequence_YieldsSuccess(byte[] bytes)
        {
            var stream = new MemoryStream(bytes);
            var source = new StreamByteSource(stream);
            var reader = new DicomReader {
                IsExplicitVR = true
            };

            var observer = new MockObserver();
            var result   = reader.Read(source, observer);

            Assert.Equal(DicomReaderResult.Success, result);
        }
Example #4
0
        public void EndRead_ValidSource_ReturnsSuccess()
        {
            using (var stream = File.OpenRead(@".\Test Data\CT1_J2KI"))
            {
                var source = new StreamByteSource(stream);
                var reader = new DicomFileReader();

                const DicomReaderResult expected = DicomReaderResult.Success;
                var actual = reader.EndRead(
                    reader.BeginRead(source, new MockObserver(), new MockObserver(), null, null));

                Assert.Equal(expected, actual);
            }
        }
Example #5
0
        public void BeginRead_ValidExplicitVRData_YieldsSuccess(DicomTag tag, DicomVR vr, string data, byte[] bytes)
        {
            var stream = new MemoryStream(bytes);
            var source = new StreamByteSource(stream);
            var reader = new DicomReader { IsExplicitVR = true };

            var observer = new LastElementObserver();
            var result = reader.EndRead(reader.BeginRead(source, observer, null, null, null));

            Assert.Equal(DicomReaderResult.Success, result);
            Assert.Equal(tag, observer.Tag);
            Assert.Equal(vr, observer.VR);
            Assert.Equal(data, observer.Data);
        }
Example #6
0
        public void EndRead_ValidSource_ReturnsSuccess()
        {
            using (var stream = File.OpenRead(@".\Test Data\CT1_J2KI"))
            {
                var source = new StreamByteSource(stream);
                var reader = new DicomFileReader();

                const DicomReaderResult expected = DicomReaderResult.Success;
                var actual = reader.EndRead(
                    reader.BeginRead(source, new MockObserver(), new MockObserver(), null, null));

                Assert.Equal(expected, actual);
            }
        }
Example #7
0
        public void BeginRead_ValidExplicitVRData_YieldsSuccess(DicomTag tag, DicomVR vr, string data, byte[] bytes)
        {
            var stream = new MemoryStream(bytes);
            var source = new StreamByteSource(stream);
            var reader = new DicomReader {
                IsExplicitVR = true
            };

            var observer = new LastElementObserver();
            var result   = reader.EndRead(reader.BeginRead(source, observer, null, null, null));

            Assert.Equal(DicomReaderResult.Success, result);
            Assert.Equal(tag, observer.Tag);
            Assert.Equal(vr, observer.VR);
            Assert.Equal(data, observer.Data);
        }
Example #8
0
        public void Read_CompressedImage_RecognizeTransferSyntax()
        {
            using var stream = File.OpenRead(TestData.Resolve("CT1_J2KI"));
            var source = new StreamByteSource(stream);
            var reader = new DicomFileReader();

            var fileMetaInfo = new DicomFileMetaInformation();
            var dataset      = new DicomDataset();

            reader.Read(
                source,
                new DicomDatasetReaderObserver(fileMetaInfo),
                new DicomDatasetReaderObserver(dataset));

            var expected = DicomTransferSyntax.JPEG2000Lossy;
            var actual   = reader.Syntax;

            Assert.Equal(expected, actual);
        }
Example #9
0
        /// <summary>
        /// Asynchronously read a DICOM file from stream.
        /// </summary>
        /// <param name="stream">Stream to read.</param>
        /// <param name="fallbackEncoding">Encoding to use if encoding cannot be obtained from DICOM file.</param>
        /// <param name="stop">Stop criterion in dataset.</param>
        /// <param name="readOption">The option how to deal with large DICOM tags like pixel data.</param>
        /// <returns>Awaitable <see cref="DicomFile"/> instance.</returns>
        public static async Task <DicomFile> OpenAsync(Stream stream, Encoding fallbackEncoding, Func <ParseState, bool> stop = null, FileReadOption readOption = FileReadOption.Default)
        {
            if (fallbackEncoding == null)
            {
                throw new ArgumentNullException(nameof(fallbackEncoding));
            }
            var df = new DicomFile();

            try
            {
                var source = new StreamByteSource(stream, readOption);
                using (var unvalidated = new UnvalidatedScope(df.Dataset))
                {
                    var reader = new DicomFileReader();
                    var result =
                        await
                        reader.ReadAsync(
                            source,
                            new DicomDatasetReaderObserver(df.FileMetaInfo),
                            new DicomDatasetReaderObserver(df.Dataset, fallbackEncoding),
                            stop).ConfigureAwait(false);

                    if (result == DicomReaderResult.Processing)
                    {
                        throw new DicomFileException(df, $"Invalid read return state: {result}");
                    }
                    if (result == DicomReaderResult.Error)
                    {
                        return(null);
                    }
                    df.IsPartial = result == DicomReaderResult.Stopped || result == DicomReaderResult.Suspended;

                    df.Format = reader.FileFormat;
                    df.Dataset.InternalTransferSyntax = reader.Syntax;

                    return(df);
                }
            }
            catch (Exception e)
            {
                throw new DicomFileException(df, e.Message, e);
            }
        }
Example #10
0
        public void Read_CompressedImage_RecognizeTransferSyntax()
        {
            using (var stream = File.OpenRead(@".\Test Data\CT1_J2KI"))
            {
                var source = new StreamByteSource(stream);
                var reader = new DicomFileReader();

                var fileMetaInfo = new DicomFileMetaInformation();
                var dataset = new DicomDataset();

                reader.Read(
                    source,
                    new DicomDatasetReaderObserver(fileMetaInfo),
                    new DicomDatasetReaderObserver(dataset));

                var expected = DicomTransferSyntax.JPEG2000Lossy;
                var actual = reader.Syntax;
                Assert.Equal(expected, actual);
            }
        }
Example #11
0
        public static DicomFile Open(Stream stream)
        {
            var df = new DicomFile();

            try {
                var source = new StreamByteSource(stream);

                var reader = new DicomFileReader();
                reader.Read(source,
                            new DicomDatasetReaderObserver(df.FileMetaInfo),
                            new DicomDatasetReaderObserver(df.Dataset));

                df.Format = reader.FileFormat;

                df.Dataset.InternalTransferSyntax = reader.Syntax;

                return(df);
            } catch (Exception e) {
                throw new DicomFileException(df, e.Message, e);
            }
        }
Example #12
0
        public async Task ReadAsync_CompressedImage_RecognizeTransferSyntax()
        {
            using (var stream = File.OpenRead(@".\Test Data\CT1_J2KI"))
            {
                var source = new StreamByteSource(stream);
                var reader = new DicomFileReader();

                var fileMetaInfo = new DicomFileMetaInformation();
                var dataset      = new DicomDataset();

                await
                reader.ReadAsync(
                    source,
                    new DicomDatasetReaderObserver(fileMetaInfo),
                    new DicomDatasetReaderObserver(dataset));

                var expected = DicomTransferSyntax.JPEG2000Lossy;
                var actual   = reader.Syntax;
                Assert.Equal(expected, actual);
            }
        }
Example #13
0
        public void Read_ValidSource_ReturnsSuccess()
        {
            using var stream = File.OpenRead(TestData.Resolve("CT1_J2KI"));
            var source = new StreamByteSource(stream);
            var reader = new DicomFileReader();

            var fileMetaInfo = new DicomFileMetaInformation();
            var dataset      = new DicomDataset();

            const DicomReaderResult expected = DicomReaderResult.Success;
            var actual = reader.Read(
                source,
                new DicomDatasetReaderObserver(fileMetaInfo),
                new DicomDatasetReaderObserver(dataset));

            Assert.Equal(expected, actual);

            var modality = dataset.GetString(DicomTag.Modality);

            Assert.Equal("CT", modality);
        }
Example #14
0
        /// <summary>
        /// Read a DICOM file from stream.
        /// </summary>
        /// <param name="stream">Stream to read.</param>
        /// <param name="fallbackEncoding">Encoding to use if encoding cannot be obtained from DICOM file.</param>
        /// <param name="stop">Stop criterion in dataset.</param>
        /// <returns>Read <see cref="DicomFile"/>.</returns>
        public static DicomFile Open(Stream stream, Encoding fallbackEncoding, Func <ParseState, bool> stop = null)
        {
            if (fallbackEncoding == null)
            {
                throw new ArgumentNullException("fallbackEncoding");
            }
            var df = new DicomFile();

            try
            {
                var source = new StreamByteSource(stream);

                var reader = new DicomFileReader();
                var result = reader.Read(
                    source,
                    new DicomDatasetReaderObserver(df.FileMetaInfo),
                    new DicomDatasetReaderObserver(df.Dataset, fallbackEncoding),
                    stop);

                if (result == DicomReaderResult.Processing)
                {
                    throw new DicomFileException(df, "Invalid read return state: {state}", result);
                }
                if (result == DicomReaderResult.Error)
                {
                    return(null);
                }
                df.IsPartial = result == DicomReaderResult.Stopped || result == DicomReaderResult.Suspended;

                df.Format = reader.FileFormat;

                df.Dataset.InternalTransferSyntax = reader.Syntax;

                return(df);
            }
            catch (Exception e)
            {
                throw new DicomFileException(df, e.Message, e);
            }
        }
Example #15
0
        public void Read_ValidSource_ReturnsSuccess()
        {
            using (var stream = File.OpenRead(@".\Test Data\CT1_J2KI"))
            {
                var source = new StreamByteSource(stream);
                var reader = new DicomFileReader();

                var fileMetaInfo = new DicomFileMetaInformation();
                var dataset = new DicomDataset();

                const DicomReaderResult expected = DicomReaderResult.Success;
                var actual = reader.Read(
                    source,
                    new DicomDatasetReaderObserver(fileMetaInfo),
                    new DicomDatasetReaderObserver(dataset));

                Assert.Equal(expected, actual);

                var modality = dataset.Get<string>(DicomTag.Modality);
                Assert.Equal("CT", modality);
            }
        }
Example #16
0
        private void ProcessPDataTF(object state)
        {
            var pdu = (PDataTF)state;

            try {
                foreach (var pdv in pdu.PDVs)
                {
                    if (_dimse == null)
                    {
                        // create stream for receiving command
                        if (_dimseStream == null)
                        {
                            _dimseStream = new MemoryStream();
                        }
                    }
                    else
                    {
                        // create stream for receiving dataset
                        if (_dimseStream == null)
                        {
                            if (_dimse.Type == DicomCommandField.CStoreRequest)
                            {
                                var pc = Association.PresentationContexts.FirstOrDefault(x => x.ID == pdv.PCID);

                                var file = new DicomFile();
                                file.FileMetaInfo.MediaStorageSOPClassUID      = pc.AbstractSyntax;
                                file.FileMetaInfo.MediaStorageSOPInstanceUID   = _dimse.Command.Get <DicomUID>(DicomTag.AffectedSOPInstanceUID);
                                file.FileMetaInfo.TransferSyntax               = pc.AcceptedTransferSyntax;
                                file.FileMetaInfo.ImplementationClassUID       = Association.RemoteImplemetationClassUID;
                                file.FileMetaInfo.ImplementationVersionName    = Association.RemoteImplementationVersion;
                                file.FileMetaInfo.SourceApplicationEntityTitle = Association.CallingAE;

                                _dimseStream = CreateCStoreReceiveStream(file);
                            }
                            else
                            {
                                _dimseStream = new MemoryStream();
                            }
                        }
                    }

                    _dimseStream.Write(pdv.Value, 0, pdv.Value.Length);

                    if (pdv.IsLastFragment)
                    {
                        if (pdv.IsCommand)
                        {
                            _dimseStream.Seek(0, SeekOrigin.Begin);

                            var command = new DicomDataset();

                            var reader = new DicomReader();
                            reader.IsExplicitVR = false;
                            reader.Read(new StreamByteSource(_dimseStream), new DicomDatasetReaderObserver(command));

                            _dimseStream = null;

                            var type = command.Get <DicomCommandField>(DicomTag.CommandField);
                            switch (type)
                            {
                            case DicomCommandField.CStoreRequest:
                                _dimse = new DicomCStoreRequest(command);
                                break;

                            case DicomCommandField.CStoreResponse:
                                _dimse = new DicomCStoreResponse(command);
                                break;

                            case DicomCommandField.CFindRequest:
                                _dimse = new DicomCFindRequest(command);
                                break;

                            case DicomCommandField.CFindResponse:
                                _dimse = new DicomCFindResponse(command);
                                break;

                            case DicomCommandField.CMoveRequest:
                                _dimse = new DicomCMoveRequest(command);
                                break;

                            case DicomCommandField.CMoveResponse:
                                _dimse = new DicomCMoveResponse(command);
                                break;

                            case DicomCommandField.CEchoRequest:
                                _dimse = new DicomCEchoRequest(command);
                                break;

                            case DicomCommandField.CEchoResponse:
                                _dimse = new DicomCEchoResponse(command);
                                break;

                            case DicomCommandField.NActionRequest:
                                _dimse = new DicomNActionRequest(command);
                                break;

                            case DicomCommandField.NActionResponse:
                                _dimse = new DicomNActionResponse(command);
                                break;

                            case DicomCommandField.NCreateRequest:
                                _dimse = new DicomNCreateRequest(command);
                                break;

                            case DicomCommandField.NCreateResponse:
                                _dimse = new DicomNCreateResponse(command);
                                break;

                            case DicomCommandField.NDeleteRequest:
                                _dimse = new DicomNDeleteRequest(command);
                                break;

                            case DicomCommandField.NDeleteResponse:
                                _dimse = new DicomNDeleteResponse(command);
                                break;

                            case DicomCommandField.NEventReportRequest:
                                _dimse = new DicomNEventReportRequest(command);
                                break;

                            case DicomCommandField.NEventReportResponse:
                                _dimse = new DicomNEventReportResponse(command);
                                break;

                            case DicomCommandField.NGetRequest:
                                _dimse = new DicomNGetRequest(command);
                                break;

                            case DicomCommandField.NGetResponse:
                                _dimse = new DicomNGetResponse(command);
                                break;

                            case DicomCommandField.NSetRequest:
                                _dimse = new DicomNSetRequest(command);
                                break;

                            case DicomCommandField.NSetResponse:
                                _dimse = new DicomNSetResponse(command);
                                break;

                            default:
                                _dimse = new DicomMessage(command);
                                break;
                            }
                            _dimse.PresentationContext = Association.PresentationContexts.FirstOrDefault(x => x.ID == pdv.PCID);
                            if (!_dimse.HasDataset)
                            {
                                if (DicomMessage.IsRequest(_dimse.Type))
                                {
                                    ThreadPool.QueueUserWorkItem(PerformDimseCallback, _dimse);
                                }
                                else
                                {
                                    _processQueue.Queue((_dimse as DicomResponse).RequestMessageID, PerformDimseCallback, _dimse);
                                }
                                _dimse = null;
                                return;
                            }
                        }
                        else
                        {
                            if (_dimse.Type != DicomCommandField.CStoreRequest)
                            {
                                _dimseStream.Seek(0, SeekOrigin.Begin);

                                var pc = Association.PresentationContexts.FirstOrDefault(x => x.ID == pdv.PCID);

                                _dimse.Dataset = new DicomDataset();
                                _dimse.Dataset.InternalTransferSyntax = pc.AcceptedTransferSyntax;

                                var source = new StreamByteSource(_dimseStream);
                                source.Endian = pc.AcceptedTransferSyntax.Endian;

                                var reader = new DicomReader();
                                reader.IsExplicitVR = pc.AcceptedTransferSyntax.IsExplicitVR;
                                reader.Read(source, new DicomDatasetReaderObserver(_dimse.Dataset));

                                _dimseStream = null;
                            }
                            else
                            {
                                var request = _dimse as DicomCStoreRequest;

                                try
                                {
                                    var dicomFile = GetCStoreDicomFile();
                                    _dimseStream = null;
                                    _isTempFile  = false;

                                    // NOTE: dicomFile will be valid with the default implementation of CreateCStoreReceiveStream() and
                                    // GetCStoreDicomFile(), but can be null if a child class overrides either method and changes behavior.
                                    // See documentation on CreateCStoreReceiveStream() and GetCStoreDicomFile() for information about why
                                    // this might be desired.
                                    request.File = dicomFile;
                                    if (request.File != null)
                                    {
                                        request.Dataset = request.File.Dataset;
                                    }
                                }
                                catch (Exception e)
                                {
                                    var fileName = "";
                                    if (_dimseStream is FileStream)
                                    {
                                        fileName = (_dimseStream as FileStream).Name;
                                    }
                                    // failed to parse received DICOM file; send error response instead of aborting connection
                                    SendResponse(new DicomCStoreResponse(request, new DicomStatus(DicomStatus.ProcessingFailure, e.Message)));
                                    Logger.Error("Error parsing C-Store dataset: " + e.ToString());
                                    (this as IDicomCStoreProvider).OnCStoreRequestException(fileName, e);
                                    return;
                                }
                            }

                            if (DicomMessage.IsRequest(_dimse.Type))
                            {
                                ThreadPool.QueueUserWorkItem(PerformDimseCallback, _dimse);
                            }
                            else
                            {
                                _processQueue.Queue((_dimse as DicomResponse).RequestMessageID, PerformDimseCallback, _dimse);
                            }
                            _dimse = null;
                        }
                    }
                }
            } catch (Exception e) {
                SendAbort(DicomAbortSource.ServiceUser, DicomAbortReason.NotSpecified);
                Logger.Error("Exception processing P-Data-TF PDU: " + e.ToString());
            } finally {
                SendNextMessage();
            }
        }
Example #17
0
        private void ProcessPDataTF(PDataTF pdu)
        {
            try {
                foreach (var pdv in pdu.PDVs)
                {
                    if (_dimse == null)
                    {
                        // create stream for receiving command
                        if (_dimseStream == null)
                        {
                            _dimseStream = new MemoryStream();
                        }
                    }
                    else
                    {
                        // create stream for receiving dataset
                        if (_dimseStream == null)
                        {
                            if (_dimse.Type == DicomCommandField.CStoreRequest)
                            {
                                var pc = Association.PresentationContexts.FirstOrDefault(x => x.ID == pdv.PCID);

                                var file = new DicomFile();
                                file.FileMetaInfo.MediaStorageSOPClassUID      = pc.AbstractSyntax;
                                file.FileMetaInfo.MediaStorageSOPInstanceUID   = _dimse.Command.Get <DicomUID>(DicomTag.AffectedSOPInstanceUID);
                                file.FileMetaInfo.TransferSyntax               = pc.AcceptedTransferSyntax;
                                file.FileMetaInfo.ImplementationClassUID       = Association.RemoteImplemetationClassUID;
                                file.FileMetaInfo.ImplementationVersionName    = Association.RemoteImplementationVersion;
                                file.FileMetaInfo.SourceApplicationEntityTitle = Association.CallingAE;

                                string fileName;
                                if (this is IDicomCStoreProvider)
                                {
                                    fileName = (this as IDicomCStoreProvider).GetTempFileName(file.FileMetaInfo.MediaStorageSOPInstanceUID);
                                }
                                else
                                {
                                    throw new DicomNetworkException("C-Store SCP not implemented");
                                }

                                file.Save(fileName);

                                _dimseStream = File.OpenWrite(fileName);
                                _dimseStream.Seek(0, SeekOrigin.End);
                            }
                            else
                            {
                                _dimseStream = new MemoryStream();
                            }
                        }
                    }

                    _dimseStream.Write(pdv.Value, 0, pdv.Value.Length);

                    if (pdv.IsLastFragment)
                    {
                        if (pdv.IsCommand)
                        {
                            _dimseStream.Seek(0, SeekOrigin.Begin);

                            var command = new DicomDataset();

                            var reader = new DicomReader();
                            reader.IsExplicitVR = false;
                            reader.Read(new StreamByteSource(_dimseStream), new DicomDatasetReaderObserver(command));

                            _dimseStream = null;

                            var type = command.Get <DicomCommandField>(DicomTag.CommandField);
                            switch (type)
                            {
                            case DicomCommandField.CStoreRequest:
                                _dimse = new DicomCStoreRequest(command);
                                break;

                            case DicomCommandField.CStoreResponse:
                                _dimse = new DicomCStoreResponse(command);
                                break;

                            case DicomCommandField.CFindRequest:
                                _dimse = new DicomCFindRequest(command);
                                break;

                            case DicomCommandField.CFindResponse:
                                _dimse = new DicomCFindResponse(command);
                                break;

                            case DicomCommandField.CMoveRequest:
                                _dimse = new DicomCMoveRequest(command);
                                break;

                            case DicomCommandField.CMoveResponse:
                                _dimse = new DicomCMoveResponse(command);
                                break;

                            case DicomCommandField.CEchoRequest:
                                _dimse = new DicomCEchoRequest(command);
                                break;

                            case DicomCommandField.CEchoResponse:
                                _dimse = new DicomCEchoResponse(command);
                                break;

                            default:
                                _dimse = new DicomMessage(command);
                                break;
                            }

                            if (!_dimse.HasDataset)
                            {
                                ThreadPool.QueueUserWorkItem(PerformDimseCallback, _dimse);
                                _dimse = null;
                                return;
                            }
                        }
                        else
                        {
                            if (_dimse.Type != DicomCommandField.CStoreRequest)
                            {
                                _dimseStream.Seek(0, SeekOrigin.Begin);

                                _dimse.Dataset = new DicomDataset();
                                _dimse.Dataset.InternalTransferSyntax = _dimse.Command.InternalTransferSyntax;

                                var source = new StreamByteSource(_dimseStream);
                                source.Endian = _dimse.Command.InternalTransferSyntax.Endian;

                                var reader = new DicomReader();
                                reader.IsExplicitVR = _dimse.Command.InternalTransferSyntax.IsExplicitVR;
                                reader.Read(source, new DicomDatasetReaderObserver(_dimse.Dataset));

                                _dimseStream = null;
                            }
                            else
                            {
                                var fileName = (_dimseStream as FileStream).Name;
                                _dimseStream.Close();
                                _dimseStream = null;

                                var request = _dimse as DicomCStoreRequest;
                                request.File = DicomFile.Open(fileName);
                                request.File.File.IsTempFile = true;
                                request.Dataset = request.File.Dataset;
                            }

                            ThreadPool.QueueUserWorkItem(PerformDimseCallback, _dimse);
                            _dimse = null;
                        }
                    }
                }
            } catch (Exception e) {
                SendAbort(DicomAbortSource.ServiceUser, DicomAbortReason.NotSpecified);
                Logger.Log(LogLevel.Error, e.ToString());
            } finally {
                SendNextMessage();
            }
        }
Example #18
-1
        public void Read_ValidExplicitVRSequence_YieldsSuccess(byte[] bytes)
        {
            var stream = new MemoryStream(bytes);
            var source = new StreamByteSource(stream);
            var reader = new DicomReader { IsExplicitVR = true };

            var observer = new MockObserver();
            var result = reader.Read(source, observer);

            Assert.Equal(DicomReaderResult.Success, result);
        }