using System; using System.Collections.Generic; using System.IO; namespace fis.Vid { public enum OperationMode { Open, Create } public enum VidImageFormat { Jpeg = 0, Png = 1, H264 = 2, Zip = 3, Diff = 4, } public class VinnoImageData : IDisposable { private OperationMode _operationMode; private readonly Stream _stream; private readonly VinnoStreamReader _reader; private readonly VinnoStreamWriter _writer; private readonly string _filePath; private readonly List _imagePositionList; private bool _disposed; private bool _closed; private readonly object _addGetLocker = new object(); private const string Header = "VINNO IMAGE DATA"; private const string CacheHeader = "VINNOIMGCACHE"; /// /// Gets the version of this image data. /// public int Version { get; } /// /// Gets the image count of this image data. /// public int ImageCount { get; private set; } /// /// Gets the probe information. /// public VinnoProbe Probe { get; private set; } /// /// Gets the image format of this image data. /// public VidImageFormat ImageFormat { get; } /// /// Gets or sets the extended data. /// public byte[] ExtendedData { get; set; } /// /// Create a VINNO Image Data. /// /// The file path to read or create. /// The operation mode, create to create a vid file, open to open a vid file. public VinnoImageData(string filePath, OperationMode mode) { try { ImageFormat = VidImageFormat.Jpeg; _filePath = filePath; _operationMode = mode; ExtendedData = new byte[0]; if (mode == OperationMode.Create) { //Create temp file. var tempFile = _filePath + ".tmp"; _stream = new FileStream(tempFile, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite); _writer = new VinnoStreamWriter(_stream); Version = 3; Probe = null; _imagePositionList = new List(); ImageCount = 0; } else { if (!File.Exists(_filePath) && File.Exists(_filePath + ".tmp")) { _filePath = _filePath + ".tmp"; } _stream = new FileStream(_filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); _reader = new VinnoStreamReader(_stream); var header = _reader.ReadString(); if (header != Header && header != CacheHeader) { _stream.Dispose(); throw new InvalidDataException("File is not a VID file."); } Version = _reader.ReadInt(); //Get probe info var probeData = _reader.ReadBytes(); Probe = VinnoProbe.FromBytes(probeData); ImageFormat = (VidImageFormat)_reader.ReadInt(); ExtendedData = _reader.ReadBytes(); //Get the index list. _imagePositionList = new List(_reader.ReadLongs()); ImageCount = _imagePositionList.Count; } } catch (Exception ex) { _stream?.Dispose(); } } /// /// Create a VINNO Image Data. /// /// public VinnoImageData(Stream stream) { try { ImageFormat = VidImageFormat.Jpeg; ExtendedData = new byte[0]; _stream = stream; _reader = new VinnoStreamReader(_stream); var header = _reader.ReadString(); if (header != Header) { _stream.Dispose(); throw new InvalidDataException("File is not a VID file."); } Version = _reader.ReadInt(); //Get probe info var probeData = _reader.ReadBytes(); Probe = VinnoProbe.FromBytes(probeData); ImageFormat = (VidImageFormat)_reader.ReadInt(); ExtendedData = _reader.ReadBytes(); //Get the index list. _imagePositionList = new List(_reader.ReadLongs()); ImageCount = _imagePositionList.Count; } catch (Exception ex) { _stream?.Dispose(); } } /// /// Add probe info into vid. /// /// public void AddProbe(VinnoProbe probe) { Probe = probe; } /// /// Add dicom info into vid /// /// public void AddExtendedData(byte[] extendedData) { ExtendedData = extendedData; } /// /// Add one image into vid. /// /// public void AddImage(VinnoImage image) { if (_closed) { throw new InvalidOperationException("ImageData closed."); } if (_operationMode != OperationMode.Create) { throw new InvalidOperationException("Can not add image under open mode."); } lock (_addGetLocker) { var postion = _stream.Position; _writer.WriteBytes(image.ToBytes()); _imagePositionList.Add(postion); ImageCount++; } } /// /// Gets one image from the vid. /// /// /// public VinnoImage GetImage(int index) { if (_closed) { throw new InvalidOperationException("ImageData closed."); } if (_operationMode != OperationMode.Open) { throw new InvalidOperationException("Can not open image under create mode."); } if (index >= ImageCount || index < 0) { throw new IndexOutOfRangeException("Can not find image Data"); } lock (_addGetLocker) { //Jump to image. _stream.Position = _imagePositionList[index]; var imageData = _reader.ReadBytes(); return VinnoImage.FromBytes(imageData); } } public void Close() { if (!_closed) { lock (_addGetLocker) { if (_operationMode == OperationMode.Create && !string.IsNullOrWhiteSpace(_filePath) && ImageCount > 0) { using (var stream = File.Create(_filePath)) { var writer = new VinnoStreamWriter(stream); writer.WriteString(Header); writer.WriteInt(Version); writer.WriteBytes(Probe.ToBytes()); writer.WriteInt((int)ImageFormat); writer.WriteBytes(ExtendedData); //Position data length = imagecount(int 4bytes) + imagecount * positionSize(long 8bytes) var positionsDataLength = _imagePositionList.Count * sizeof(long) + 4; var offset = stream.Length + positionsDataLength; for (var i = 0; i < _imagePositionList.Count; i++) { _imagePositionList[i] = _imagePositionList[i] + offset; } writer.WriteLongs(_imagePositionList.ToArray()); _stream.Position = 0; _stream.CopyTo(stream); } } _stream?.Dispose(); if (_operationMode == OperationMode.Create && !string.IsNullOrWhiteSpace(_filePath)) { var tempFile = _filePath + ".tmp"; File.Delete(tempFile); } } _closed = true; } } protected void Dispose(bool disposing) { if (!_disposed) { Close(); } _disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }