public override void Flush() { if (UnderlyingIO == null) { throw new InvalidOperationException( @"UnderlyingI stream missing. Tilepart headers should be written after codestream headers"); } if (!IsOpened) { throw new InvalidOperationException(String.Concat( "Trying to flush to IO stream ", "a closed tile-part")); } if (_offset == OFFSET_NOT_SET) { _offset = (Parent as JP2Codestream).AssignOffset(this); } // SOT marker includes the full tile-part length we should write the // SOT marker after all the packets have been added, and we know in // advance what is the full tile-part length (markers and packets). UnderlyingIO.Seek(Position, SeekOrigin.Begin); _sot.WriteMarkerSegment(UnderlyingIO); foreach (var plt in _pltMarkers) { plt.WriteMarkerSegment(UnderlyingIO); } MarkerSegment.WriteMarker(MarkerType.SOD, UnderlyingIO); // can be safely closed and reopened from the underlying stream. IsFlushed = true; }
public override void Flush() { if (_offset == OFFSET_NOT_SET) { throw new InvalidOperationException( "Should bind CodestreamNode to a stream"); } // Writes the main headers of this codestream The headers include // SOC and every other marker in the Markers collection except TLM. // TLM is written when the codestream is sealed, after all of the // tileparts are generated. To write the TLM and EOC marker invoke // WriteFinalizers(). UnderlyingIO.Seek(Position, SeekOrigin.Begin); int offset = 0; offset += MarkerSegment.WriteMarker(MarkerType.SOC, UnderlyingIO); offset += Markers[MarkerType.SIZ].WriteMarkerSegment(UnderlyingIO); offset += Markers[MarkerType.COD].WriteMarkerSegment(UnderlyingIO); offset += Markers[MarkerType.QCD].WriteMarkerSegment(UnderlyingIO); var optionalMarkers = Markers.Keys.Except(MandatoryMarkers); foreach (var opt in optionalMarkers) { offset += Markers[opt].WriteMarkerSegment(UnderlyingIO); } foreach (var tlm in _tlmMarkers) { offset += tlm.WriteMarkerSegment(UnderlyingIO); } // flush only the ones that were not flushed incrementally // by user code. foreach (var tp in _tileparts.Where(tp => !tp.IsFlushed)) { tp.Flush(); } long tpLength = _tileparts.Sum(tp => tp.Length); // account for all headers, all tile-parts and EOC marker Length = FirstChildOffset + tpLength + MarkerSegment.MarkerLength; long eocOffset = Position + FirstChildOffset + tpLength; UnderlyingIO.Seek(eocOffset, SeekOrigin.Begin); MarkerSegment.WriteMarker(MarkerType.EOC, UnderlyingIO); // can be safely closed an re-opened from the underlying stream IsFlushed = true; }
private void ConstructTilesFromCodestream() { if (_sotOffset == 0) { throw new InvalidOperationException( "SOT offset uninitialized, cannot traverse tile-parts " + "before main header was parsed and first tile part" + " was encountered"); } int tileCount = Tiles.Count(); UnderlyingIO.Seek(Position + _sotOffset, SeekOrigin.Begin); long offset = _sotOffset; MarkerType type; while ((type = MarkerSegment.Peek(UnderlyingIO)) != MarkerType.EOC) { if (type != MarkerType.SOT) { throw new InvalidOperationException( "Expected only SOT markers in codestream traversal"); } // get the length of the tile part from the SOT and continue as // if we have read a TLM entry. SotMarker sot = MarkerSegment.Open(UnderlyingIO) as SotMarker; if (sot.TileIndex >= tileCount) { throw new ArgumentOutOfRangeException( "SOT TileIndex is too large for number of tiles" + " calculated from SIZ tile and image size"); } AddTilePart(offset, sot.TileIndex, sot.TilePartLength); offset += sot.TilePartLength; // skip to the next marker segment, // account for the already read SOT_MARKER long skip = sot.TilePartLength; skip -= SotMarker.SOT_MARKER_LENGTH; skip -= MarkerSegment.MarkerLength; UnderlyingIO.Seek(skip, SeekOrigin.Current); } return; }
private static Dictionary <ushort, byte[]> ReadSegments(Stream str) { var rawSegments = new Dictionary <ushort, byte[]>(); for (ushort mrkType = str.ReadUInt16(); mrkType != (ushort)MarkerType.SOT; mrkType = str.ReadUInt16()) { if (MarkerSegment.IsSegment((MarkerType)mrkType)) { ushort mrkLength = str.ReadUInt16(); byte[] segment = new byte[mrkLength - 2]; str.Read(segment, 0, mrkLength - 2); rawSegments[mrkType] = segment; } } return(rawSegments); }
internal override CodestreamNode Open() { if (IsOpened) { return(this); } UnderlyingIO.Seek(Position, SeekOrigin.Begin); MarkerType marker = MarkerSegment.Peek(UnderlyingIO); if (marker != MarkerType.SOT) { throw new ArgumentException( "SOT marker expected but was not found"); } List <PltMarker> pltMarkers = new List <PltMarker>(); int zIdx = -1; // current z-idx of plt markers bool isZOrderConsistent = true; // true iff every consequent plt // maintains ascending order from zero, without gaps. long offset = 0; while (MarkerSegment.Peek(UnderlyingIO) != MarkerType.SOD) { MarkerSegment ms = MarkerSegment.Open(UnderlyingIO); switch (ms.Type) { case MarkerType.SOT: _sot = ms as SotMarker; break; case MarkerType.PLT: var plt = ms as PltMarker; isZOrderConsistent &= (++zIdx) == plt.ZIndex; pltMarkers.Add(plt); break; case MarkerType.COD: case MarkerType.COC: case MarkerType.QCD: case MarkerType.QCC: throw new NotSupportedException( "Codestream and quantization markers are " + " not supported in tile part header"); default: break; } offset += MarkerSegment.MarkerLength + ms.Length; } _sodOffset = offset; if (!isZOrderConsistent) { // needs sorting! pltMarkers.Sort((PltMarker pltX, PltMarker pltY) => pltX.ZIndex.CompareTo(pltY.ZIndex)); } if (!pltMarkers.Any() && Length > EMPTY_TILEPART_LENGTH) { throw new NotSupportedException( "packet lengths are not specified in a non empty tile-part" + " decoding packet headers is not supported yet"); } _pltMarkers = pltMarkers; // flatten uint packOffset = 0; foreach (var plt in pltMarkers) { foreach (var packLength in plt) { packOffset += packLength; _packetOffsets.Add(packOffset); } } // read and parsed successfully. IsOpened = true; return(this); }
internal override CodestreamNode Open() { if (IsOpened) { return(this); } UnderlyingIO.Seek(Position, SeekOrigin.Begin); if (MarkerSegment.Peek(UnderlyingIO) != MarkerType.SOC) { throw new ArgumentException( "expected SOC marker at stream position: " + Position); } var markers = new Dictionary <MarkerType, MarkerSegment>(); bool isZOrderConsistent = true; // true iff every consequent tlm // maintains ascending order from zero, without gaps. int zIdx = -1; // current z-index of plt markers List <TlmMarker> tlmMarkers = new List <TlmMarker>(); MarkerSegment ms; long offset = 0; // offset from the beginning of the codestream while (MarkerSegment.Peek(UnderlyingIO) != MarkerType.SOT) { ms = MarkerSegment.Open(UnderlyingIO); switch (ms.Type) { case MarkerType.SIZ: case MarkerType.COD: case MarkerType.QCD: if (markers.ContainsKey(ms.Type)) { throw new InvalidDataException( "Already have a " + ms.Type + "marker"); } markers[ms.Type] = ms; break; case MarkerType.TLM: var tlm = ms as TlmMarker; isZOrderConsistent &= (++zIdx) == tlm.ZIndex; tlmMarkers.Add(tlm); break; case MarkerType.COC: case MarkerType.QCC: throw new NotSupportedException( "Codestream and Quantization markers for specific" + " components are not supported in main header"); default: break; } offset += MarkerSegment.MarkerLength + ms.Length; } _sotOffset = offset; Markers = markers; if (!isZOrderConsistent) { // need sorting! tlmMarkers.Sort((TlmMarker tlmX, TlmMarker tlmY) => tlmX.ZIndex.CompareTo(tlmY.ZIndex)); } Tiles = ConstructTiles(); if (tlmMarkers.Any()) { ConstructTilesFromTlm(tlmMarkers); } else { ConstructTilesFromCodestream(); } // parsed and opened successfully. IsOpened = true; return(this); }