public ShpReader(Stream stream) { imageCount = stream.ReadUInt16(); stream.Position += 4; var width = stream.ReadUInt16(); var height = stream.ReadUInt16(); Size = new Size(width, height); stream.Position += 4; var headers = new ImageHeader[imageCount]; Frames = headers.AsReadOnly(); for (var i = 0; i < headers.Length; i++) headers[i] = new ImageHeader(stream, this); // Skip eof and zero headers stream.Position += 16; var offsets = headers.ToDictionary(h => h.FileOffset, h => h); for (var i = 0; i < imageCount; i++) { var h = headers[i]; if (h.Format == Format.Format20) h.RefImage = headers[i - 1]; else if (h.Format == Format.Format40 && !offsets.TryGetValue(h.RefOffset, out h.RefImage)) throw new InvalidDataException("Reference doesnt point to image data {0}->{1}".F(h.FileOffset, h.RefOffset)); } shpBytesFileOffset = stream.Position; shpBytes = stream.ReadBytes((int)(stream.Length - stream.Position)); foreach (var h in headers) Decompress(h); }
void Decompress(Stream stream, ImageHeader h) { if (recurseDepth > ImageCount) throw new InvalidDataException("Format20/40 headers contain infinite loop"); switch(h.Format) { case Format.Format20: case Format.Format40: { if (h.RefImage.Image == null) { ++recurseDepth; Decompress(stream, h.RefImage); --recurseDepth; } h.Image = CopyImageData(h.RefImage.Image); Format40.DecodeInto(ReadCompressedData(stream, h), h.Image); break; } case Format.Format80: { var imageBytes = new byte[Width * Height]; Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes); h.Image = imageBytes; break; } default: throw new InvalidDataException(); } }
static byte[] ReadCompressedData(Stream stream, ImageHeader h) { stream.Position = h.Offset; // TODO: Actually, far too big. There's no length field with the correct length though :( var compressedLength = (int)(stream.Length - stream.Position); var compressedBytes = new byte[ compressedLength ]; stream.Read( compressedBytes, 0, compressedLength ); return compressedBytes; }
public static void Write(Stream s, Size size, IEnumerable<byte[]> frames) { var compressedFrames = frames.Select(f => Format80.Encode(f)).ToList(); // note: end-of-file and all-zeroes headers var dataOffset = 14 + (compressedFrames.Count + 2) * 8; using (var bw = new BinaryWriter(s)) { bw.Write((ushort)compressedFrames.Count); bw.Write((ushort)0); bw.Write((ushort)0); bw.Write((ushort)size.Width); bw.Write((ushort)size.Height); bw.Write((uint)0); foreach (var f in compressedFrames) { var ih = new ImageHeader { Format = Format.Format80, FileOffset = (uint)dataOffset }; dataOffset += f.Length; ih.WriteTo(bw); } var eof = new ImageHeader { FileOffset = (uint)dataOffset }; eof.WriteTo(bw); var allZeroes = new ImageHeader { }; allZeroes.WriteTo(bw); foreach (var f in compressedFrames) bw.Write(f); } }
void Decompress(ImageHeader h) { // No extra work is required for empty frames if (h.Size.Width == 0 || h.Size.Height == 0) return; if (recurseDepth > imageCount) throw new InvalidDataException("Format20/40 headers contain infinite loop"); switch (h.Format) { case Format.Format20: case Format.Format40: { if (h.RefImage.Data == null) { ++recurseDepth; Decompress(h.RefImage); --recurseDepth; } h.Data = CopyImageData(h.RefImage.Data); Format40.DecodeInto(shpBytes, h.Data, (int)(h.FileOffset - shpBytesFileOffset)); break; } case Format.Format80: { var imageBytes = new byte[Size.Width * Size.Height]; Format80.DecodeInto(shpBytes, imageBytes, (int)(h.FileOffset - shpBytesFileOffset)); h.Data = imageBytes; break; } default: throw new InvalidDataException(); } }