diff --git a/src/ImageProcessor/Formats/Png/PngEncoder.cs b/src/ImageProcessor/Formats/Png/PngEncoder.cs
index ba404518d..786d02a85 100644
--- a/src/ImageProcessor/Formats/Png/PngEncoder.cs
+++ b/src/ImageProcessor/Formats/Png/PngEncoder.cs
@@ -14,17 +14,9 @@ namespace ImageProcessor.Formats
public class PngEncoder : IImageEncoder
{
///
- /// The maximum block size.
+ /// The maximum block size, defaults at 64k for uncompressed blocks.
///
- private const int MaxBlockSize = 0xFFFF;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public PngEncoder()
- {
- this.Gamma = 2.2f;
- }
+ private const int MaxBlockSize = 65535;
///
/// Gets or sets the quality of output for images.
@@ -40,40 +32,23 @@ namespace ImageProcessor.Formats
///
/// The compression level 1-9.
- /// TODO: Get other compression levels to work. Something is cutting of image content.
/// Defaults to 6.
///
public int CompressionLevel { get; set; } = 6;
///
- /// Gets or sets a value indicating whether this encoder
- /// will write the image uncompressed the stream.
- ///
- ///
- /// true if the image should be written uncompressed to
- /// the stream; otherwise, false.
- ///
- // TODO: We can't quickly return a color to non-premultiplied with this method.
- // Should we remove?
- //public bool IsWritingUncompressed { get; set; }
-
- ///
- /// Gets or sets a value indicating whether this instance is writing
+ /// Gets or sets a value indicating whether this instance should write
/// gamma information to the stream. The default value is false.
///
- ///
- /// True if this instance is writing gamma
- /// information to the stream; otherwise, false.
- ///
- public bool IsWritingGamma { get; set; }
+ public bool WriteGamma { get; set; }
///
/// Gets or sets the gamma value, that will be written
- /// the the stream, when the property
- /// is set to true. The default value is 2.2f.
+ /// the the stream, when the property
+ /// is set to true. The default value is 2.2F.
///
/// The gamma value of the image.
- public double Gamma { get; set; }
+ public double Gamma { get; set; } = 2.2F;
///
public bool IsSupportedFileExtension(string extension)
@@ -111,9 +86,9 @@ namespace ImageProcessor.Formats
{
Width = image.Width,
Height = image.Height,
- ColorType = 6,
+ ColorType = 6, // Each pixel is an R,G,B triple, followed by an alpha sample.
BitDepth = 8,
- FilterMethod = 0,
+ FilterMethod = 0, // None
CompressionMethod = 0,
InterlaceMethod = 0
};
@@ -121,16 +96,7 @@ namespace ImageProcessor.Formats
this.WriteHeaderChunk(stream, header);
this.WritePhysicalChunk(stream, image);
this.WriteGammaChunk(stream);
-
- //if (this.IsWritingUncompressed)
- //{
- // this.WriteDataChunksFast(stream, image);
- //}
- //else
- //{
this.WriteDataChunks(stream, image);
- //}
-
this.WriteEndChunk(stream);
stream.Flush();
}
@@ -187,6 +153,7 @@ namespace ImageProcessor.Formats
Image image = imageBase as Image;
if (image != null && image.HorizontalResolution > 0 && image.VerticalResolution > 0)
{
+ // 39.3700787 = inches in a meter.
int dpmX = (int)Math.Round(image.HorizontalResolution * 39.3700787d);
int dpmY = (int)Math.Round(image.VerticalResolution * 39.3700787d);
@@ -207,7 +174,7 @@ namespace ImageProcessor.Formats
/// The containing image data.
private void WriteGammaChunk(Stream stream)
{
- if (this.IsWritingGamma)
+ if (this.WriteGamma)
{
int gammaValue = (int)(this.Gamma * 100000f);
@@ -224,78 +191,6 @@ namespace ImageProcessor.Formats
}
}
- ///
- /// Writes the pixel information to the stream.
- ///
- /// The containing image data.
- /// The image base.
- private void WriteDataChunksFast(Stream stream, ImageBase imageBase)
- {
- float[] pixels = imageBase.Pixels;
-
- // Convert the pixel array to a new array for adding
- // the filter byte.
- byte[] data = new byte[(imageBase.Width * imageBase.Height * 4) + imageBase.Height];
-
- int rowLength = (imageBase.Width * 4) + 1;
-
- for (int y = 0; y < imageBase.Height; y++)
- {
- data[y * rowLength] = 0;
- Array.Copy(pixels, y * imageBase.Width * 4, data, (y * rowLength) + 1, imageBase.Width * 4);
- }
-
- Adler32 adler32 = new Adler32();
- adler32.Update(data);
-
- using (MemoryStream tempStream = new MemoryStream())
- {
- int remainder = data.Length;
-
- int blockCount;
- if ((data.Length % MaxBlockSize) == 0)
- {
- blockCount = data.Length / MaxBlockSize;
- }
- else
- {
- blockCount = (data.Length / MaxBlockSize) + 1;
- }
-
- // Write headers
- tempStream.WriteByte(0x78);
- tempStream.WriteByte(0xDA);
-
- for (int i = 0; i < blockCount; i++)
- {
- // Write the length
- ushort length = (ushort)((remainder < MaxBlockSize) ? remainder : MaxBlockSize);
-
- tempStream.WriteByte(length == remainder ? (byte)0x01 : (byte)0x00);
-
- tempStream.Write(BitConverter.GetBytes(length), 0, 2);
-
- // Write one's compliment of length
- tempStream.Write(BitConverter.GetBytes((ushort)~length), 0, 2);
-
- // Write blocks
- tempStream.Write(data, i * MaxBlockSize, length);
-
- // Next block
- remainder -= MaxBlockSize;
- }
-
- WriteInteger(tempStream, (int)adler32.Value);
-
- tempStream.Seek(0, SeekOrigin.Begin);
-
- byte[] zipData = new byte[tempStream.Length];
- tempStream.Read(zipData, 0, (int)tempStream.Length);
-
- this.WriteChunk(stream, PngChunkTypes.Data, zipData);
- }
- }
-
///
/// Writes the pixel information to the stream.
///
@@ -367,17 +262,13 @@ namespace ImageProcessor.Formats
{
memoryStream = new MemoryStream();
- // TODO: Get this working!
- //using (ZlibOutputStream outputStream = new ZlibOutputStream(memoryStream, this.CompressionLevel))
- using (DeflaterOutputStream outputStream = new DeflaterOutputStream(memoryStream))
+ using (ZlibOutputStream outputStream = new ZlibOutputStream(memoryStream, this.CompressionLevel))
{
outputStream.Write(data, 0, data.Length);
- outputStream.Flush();
- outputStream.Finish();
-
- bufferLength = (int)memoryStream.Length;
- buffer = memoryStream.ToArray();
}
+
+ bufferLength = (int)memoryStream.Length;
+ buffer = memoryStream.ToArray();
}
finally
{
diff --git a/src/ImageProcessor/Formats/Png/Zlib/Adler32.cs b/src/ImageProcessor/Formats/Png/Zlib/Adler32.cs
index 12cd0ca9f..25bc74853 100644
--- a/src/ImageProcessor/Formats/Png/Zlib/Adler32.cs
+++ b/src/ImageProcessor/Formats/Png/Zlib/Adler32.cs
@@ -52,9 +52,9 @@ namespace ImageProcessor.Formats
/// checked separately. (Any sequence of zeroes has a Fletcher
/// checksum of zero.)"
///
- ///
- ///
- public sealed class Adler32 : IChecksum
+ ///
+ ///
+ internal sealed class Adler32 : IChecksum
{
///
/// largest prime smaller than 65536
@@ -67,21 +67,18 @@ namespace ImageProcessor.Formats
private uint checksum;
///
- /// Initializes a new instance of the class. The checksum starts off with a value of 1.
+ /// Initializes a new instance of the class.
+ /// The checksum starts off with a value of 1.
///
public Adler32()
{
this.Reset();
}
- ///
- /// Returns the Adler32 data checksum computed so far.
- ///
+ ///
public long Value => this.checksum;
- ///
- /// Resets the Adler32 checksum to the initial value.
- ///
+ ///
public void Reset()
{
this.checksum = 1;
@@ -106,12 +103,7 @@ namespace ImageProcessor.Formats
this.checksum = (s2 << 16) + s1;
}
- ///
- /// Updates the checksum with an array of bytes.
- ///
- ///
- /// The source of the data to update with.
- ///
+ ///
public void Update(byte[] buffer)
{
if (buffer == null)
@@ -122,18 +114,7 @@ namespace ImageProcessor.Formats
this.Update(buffer, 0, buffer.Length);
}
- ///
- /// Updates the checksum with the bytes taken from the array.
- ///
- ///
- /// an array of bytes
- ///
- ///
- /// the start of the data used for this update
- ///
- ///
- /// the number of bytes to use for this update
- ///
+ ///
public void Update(byte[] buffer, int offset, int count)
{
if (buffer == null)
diff --git a/src/ImageProcessor/Formats/Png/Zlib/Crc32.cs b/src/ImageProcessor/Formats/Png/Zlib/Crc32.cs
index 70cceb0a2..d2a3e6670 100644
--- a/src/ImageProcessor/Formats/Png/Zlib/Crc32.cs
+++ b/src/ImageProcessor/Formats/Png/Zlib/Crc32.cs
@@ -12,6 +12,7 @@ namespace ImageProcessor.Formats
/// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
///
///
+ ///
/// Polynomials over GF(2) are represented in binary, one bit per coefficient,
/// with the lowest powers in the most significant bit. Then adding polynomials
/// is just exclusive-or, and multiplying a polynomial by x is a right shift by
@@ -19,7 +20,8 @@ namespace ImageProcessor.Formats
/// polynomial q, also with the lowest power in the most significant bit (so the
/// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
/// where a mod b means the remainder after dividing a by b.
- ///
+ ///
+ ///
/// This calculation is done using the shift-register method of multiplying and
/// taking the remainder. The register is initialized to zero, and for each
/// incoming bit, x^32 is added mod p to the register if the bit is a one (where
@@ -27,15 +29,17 @@ namespace ImageProcessor.Formats
/// x (which is shifting right by one and adding x^32 mod p if the bit shifted
/// out is a one). We start with the highest power (least significant bit) of
/// q and repeat for all eight bits of q.
- ///
+ ///
+ ///
/// The table is simply the CRC of all possible eight bit values. This is all
/// the information needed to generate CRC's on data a byte at a time for all
/// combinations of CRC register values and incoming bytes.
+ ///
///
- public sealed class Crc32 : IChecksum
+ internal sealed class Crc32 : IChecksum
{
///
- /// The crc seed
+ /// The cycle redundancy check seed
///
private const uint CrcSeed = 0xFFFFFFFF;
@@ -99,13 +103,11 @@ namespace ImageProcessor.Formats
};
///
- /// The crc data checksum so far.
+ /// The data checksum so far.
///
private uint crc;
- ///
- /// Gets or sets the CRC32 data checksum computed so far.
- ///
+ ///
public long Value
{
get
@@ -119,16 +121,14 @@ namespace ImageProcessor.Formats
}
}
- ///
- /// Resets the CRC32 data checksum as if no update was ever called.
- ///
+ ///
public void Reset()
{
this.crc = 0;
}
///
- /// Updates the checksum with the int bval.
+ /// Updates the checksum with the given value.
///
/// The byte is taken as the lower 8 bits of value.
public void Update(int value)
@@ -138,12 +138,7 @@ namespace ImageProcessor.Formats
this.crc ^= CrcSeed;
}
- ///
- /// Updates the checksum with the bytes taken from the array.
- ///
- ///
- /// buffer an array of bytes
- ///
+ ///
public void Update(byte[] buffer)
{
if (buffer == null)
@@ -154,18 +149,7 @@ namespace ImageProcessor.Formats
this.Update(buffer, 0, buffer.Length);
}
- ///
- /// Adds the byte array to the data checksum.
- ///
- ///
- /// The buffer which contains the data
- ///
- ///
- /// The offset in the buffer where the data starts
- ///
- ///
- /// The number of data bytes to update the CRC with.
- ///
+ ///
public void Update(byte[] buffer, int offset, int count)
{
if (buffer == null)
@@ -192,16 +176,5 @@ namespace ImageProcessor.Formats
this.crc ^= CrcSeed;
}
-
- ///
- /// Computes the crc value for the given byte.
- ///
- /// The previous value.
- /// The byte to compute against.
- /// The
- internal static uint ComputeCrc32(uint oldCrc, byte value)
- {
- return CrcTable[(oldCrc ^ value) & 0xFF] ^ (oldCrc >> 8);
- }
}
}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/DeflateStrategy.cs b/src/ImageProcessor/Formats/Png/Zlib/DeflateStrategy.cs
deleted file mode 100644
index f3655af8b..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/DeflateStrategy.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageProcessor.Formats
-{
- ///
- /// Strategies for deflater
- ///
- public enum DeflateStrategy
- {
- ///
- /// The default strategy
- ///
- Default = 0,
-
- ///
- /// This strategy will only allow longer string repetitions. It is
- /// useful for random data with a small character set.
- ///
- Filtered = 1,
-
- ///
- /// This strategy will not look for string repetitions at all. It
- /// only encodes with Huffman trees (which means, that more common
- /// characters get a smaller encoding.
- ///
- HuffmanOnly = 2
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/Deflater.cs b/src/ImageProcessor/Formats/Png/Zlib/Deflater.cs
deleted file mode 100644
index eccbab825..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/Deflater.cs
+++ /dev/null
@@ -1,561 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageProcessor.Formats
-{
- using System;
-
- ///
- /// This is the Deflater class. The deflater class compresses input
- /// with the deflate algorithm described in RFC 1951. It has several
- /// compression levels and three different strategies described below.
- ///
- /// This class is not thread safe. This is inherent in the API, due
- /// to the split of deflate and setInput.
- ///
- /// author of the original java version : Jochen Hoenicke
- ///
- public class Deflater
- {
- /*
- * The Deflater can do the following state transitions:
- *
- * (1) -> INIT_STATE ----> INIT_FINISHING_STATE ---.
- * / | (2) (5) |
- * / v (5) |
- * (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3)
- * \ | (3) | ,--------'
- * | | | (3) /
- * v v (5) v v
- * (1) -> BUSY_STATE ----> FINISHING_STATE
- * | (6)
- * v
- * FINISHED_STATE
- * \_____________________________________/
- * | (7)
- * v
- * CLOSED_STATE
- *
- * (1) If we should produce a header we start in INIT_STATE, otherwise
- * we start in BUSY_STATE.
- * (2) A dictionary may be set only when we are in INIT_STATE, then
- * we change the state as indicated.
- * (3) Whether a dictionary is set or not, on the first call of deflate
- * we change to BUSY_STATE.
- * (4) -- intentionally left blank -- :)
- * (5) FINISHING_STATE is entered, when flush() is called to indicate that
- * there is no more INPUT. There are also states indicating, that
- * the header wasn't written yet.
- * (6) FINISHED_STATE is entered, when everything has been flushed to the
- * internal pending output buffer.
- * (7) At any time (7)
- *
- */
-
- ///
- /// The best and slowest compression level. This tries to find very
- /// long and distant string repetitions.
- ///
- public const int BestCompression = 9;
-
- ///
- /// The worst but fastest compression level.
- ///
- public const int BestSpeed = 1;
-
- ///
- /// The default compression level.
- ///
- public const int DefaultCompression = -1;
-
- ///
- /// This level won't compress at all but output uncompressed blocks.
- ///
- public const int NoCompression = 0;
-
- ///
- /// The compression method. This is the only method supported so far.
- /// There is no need to use this constant at all.
- ///
- public const int Deflated = 8;
-
- ///
- /// The is dictionary set flag.
- ///
- private const int IsSetdict = 0x01;
-
- ///
- /// Flags whether flushing.
- ///
- private const int IsFlushing = 0x04;
-
- ///
- /// Flags whether finishing.
- ///
- private const int IsFinishing = 0x08;
-
- ///
- /// The initial stat flag
- ///
- private const int InitState = 0x00;
-
- ///
- /// Flags setting the dictionary.
- ///
- private const int SetdictState = 0x01;
-
- ///
- /// The busy state flag.
- ///
- private const int BusyState = 0x10;
-
- ///
- /// The flushing state flag.
- ///
- private const int FlushingState = 0x14;
-
- ///
- /// The finishing state flag.
- ///
- private const int FinishingState = 0x1c;
-
- ///
- /// The finished state flag.
- ///
- private const int FinishedState = 0x1e;
-
- ///
- /// The closed state flag.
- ///
- private const int ClosedState = 0x7f;
-
- ///
- /// The pending output.
- ///
- private readonly DeflaterPending pending;
-
- ///
- /// If true no Zlib/RFC1950 headers or footers are generated
- ///
- private readonly bool noZlibHeaderOrFooter;
-
- ///
- /// The deflater engine.
- ///
- private readonly DeflaterEngine engine;
-
- ///
- /// Compression level.
- ///
- private int deflaterLevel;
-
- ///
- /// The current state.
- ///
- private int state;
-
- ///
- /// The total bytes of output written.
- ///
- private long totalOut;
-
- ///
- /// Initializes a new instance of the class with the default compression level.
- ///
- public Deflater()
- : this(DefaultCompression, false)
- {
- }
-
- ///
- /// Initializes a new instance of the class with the given compressin level.
- ///
- ///
- /// The compression level, a value between NoCompression and BestCompression, or DefaultCompression.
- ///
- /// If level is out of range.
- public Deflater(int level)
- : this(level, false)
- {
- }
-
- ///
- /// Initializes a new instance of the class with the given compressin level.
- ///
- ///
- /// The compression level, a value between NoCompression and BestCompression, or DefaultCompression.
- ///
- ///
- /// True, if we should suppress the Zlib/RFC1950 header at the
- /// beginning and the adler checksum at the end of the output. This is
- /// useful for the GZIP/PKZIP formats.
- ///
- /// if lvl is out of range.
- public Deflater(int level, bool noZlibHeaderOrFooter)
- {
- if (level == DefaultCompression)
- {
- level = 6;
- }
- else if (level < NoCompression || level > BestCompression)
- {
- throw new ArgumentOutOfRangeException(nameof(level));
- }
-
- this.pending = new DeflaterPending();
- this.engine = new DeflaterEngine(this.pending);
- this.noZlibHeaderOrFooter = noZlibHeaderOrFooter;
- this.SetStrategy(DeflateStrategy.Default);
- this.SetLevel(level);
- this.Reset();
- }
-
- ///
- /// Gets the current adler checksum of the data that was processed so far.
- ///
- public int Adler => this.engine.Adler;
-
- ///
- /// Gets the number of input bytes processed so far.
- ///
- public long TotalIn => this.engine.TotalIn;
-
- ///
- /// Gets the number of output bytes so far.
- ///
- public long TotalOut => this.totalOut;
-
- ///
- /// Returns true if the stream was finished and no more output bytes
- /// are available.
- ///
- public bool IsFinished => (this.state == FinishedState) && this.pending.IsFlushed;
-
- ///
- /// Returns true, if the input buffer is empty.
- /// You should then call setInput().
- /// NOTE: This method can also return true when the stream
- /// was finished.
- ///
- public bool IsNeedingInput => this.engine.NeedsInput();
-
- ///
- /// Resets the deflater. The deflater acts afterwards as if it was
- /// just created with the same compression level and strategy as it
- /// had before.
- ///
- public void Reset()
- {
- this.state = this.noZlibHeaderOrFooter ? BusyState : InitState;
- this.totalOut = 0;
- this.pending.Reset();
- this.engine.Reset();
- }
-
- ///
- /// Flushes the current input block. Further calls to deflate() will
- /// produce enough output to inflate everything in the current input
- /// block. This is not part of Sun's JDK so I have made it package
- /// private. It is used by DeflaterOutputStream to implement
- /// flush().
- ///
- public void Flush()
- {
- this.state |= IsFlushing;
- }
-
- ///
- /// Finishes the deflater with the current input block. It is an error
- /// to give more input after this method was called. This method must
- /// be called to force all bytes to be flushed.
- ///
- public void Finish()
- {
- this.state |= IsFlushing | IsFinishing;
- }
-
- ///
- /// Sets the data which should be compressed next. This should be only
- /// called when needsInput indicates that more input is needed.
- /// If you call setInput when needsInput() returns false, the
- /// previous input that is still pending will be thrown away.
- /// The given byte array should not be changed, before needsInput() returns
- /// true again.
- /// This call is equivalent to setInput(input, 0, input.length).
- ///
- ///
- /// the buffer containing the input data.
- ///
- ///
- /// if the buffer was finished() or ended().
- ///
- public void SetInput(byte[] input)
- {
- this.SetInput(input, 0, input.Length);
- }
-
- ///
- /// Sets the data which should be compressed next. This should be
- /// only called when needsInput indicates that more input is needed.
- /// The given byte array should not be changed, before needsInput() returns
- /// true again.
- ///
- ///
- /// the buffer containing the input data.
- ///
- ///
- /// the start of the data.
- ///
- ///
- /// the number of data bytes of input.
- ///
- ///
- /// if the buffer was Finish()ed or if previous input is still pending.
- ///
- public void SetInput(byte[] input, int offset, int count)
- {
- if ((this.state & IsFinishing) != 0)
- {
- throw new InvalidOperationException("Finish() already called");
- }
-
- this.engine.SetInput(input, offset, count);
- }
-
- ///
- /// Sets the compression level. There is no guarantee of the exact
- /// position of the change, but if you call this when needsInput is
- /// true the change of compression level will occur somewhere near
- /// before the end of the so far given input.
- ///
- ///
- /// the new compression level.
- ///
- public void SetLevel(int level)
- {
- if (level == DefaultCompression)
- {
- level = 6;
- }
- else if (level < NoCompression || level > BestCompression)
- {
- throw new ArgumentOutOfRangeException(nameof(level));
- }
-
- if (this.deflaterLevel != level)
- {
- this.deflaterLevel = level;
- this.engine.SetLevel(level);
- }
- }
-
- ///
- /// Get current compression level
- ///
- /// Returns the current compression level
- public int GetLevel()
- {
- return this.deflaterLevel;
- }
-
- ///
- /// Sets the compression strategy. Strategy is one of
- /// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED. For the exact
- /// position where the strategy is changed, the same as for
- /// SetLevel() applies.
- ///
- ///
- /// The new compression strategy.
- ///
- public void SetStrategy(DeflateStrategy strategy)
- {
- this.engine.Strategy = strategy;
- }
-
- ///
- /// Deflates the current input block with to the given array.
- ///
- ///
- /// The buffer where compressed data is stored
- ///
- ///
- /// The number of compressed bytes added to the output, or 0 if either
- /// IsNeedingInput() or IsFinished returns true or length is zero.
- ///
- public int Deflate(byte[] output)
- {
- return this.Deflate(output, 0, output.Length);
- }
-
- ///
- /// Deflates the current input block to the given array.
- ///
- ///
- /// Buffer to store the compressed data.
- ///
- ///
- /// Offset into the output array.
- ///
- ///
- /// The maximum number of bytes that may be stored.
- ///
- ///
- /// The number of compressed bytes added to the output, or 0 if either
- /// needsInput() or finished() returns true or length is zero.
- ///
- ///
- /// If Finish() was previously called.
- ///
- ///
- /// If offset or length don't match the array length.
- ///
- public int Deflate(byte[] output, int offset, int length)
- {
- int origLength = length;
-
- if (this.state == ClosedState)
- {
- throw new InvalidOperationException("Deflater closed");
- }
-
- if (this.state < BusyState)
- {
- // output header
- int header = (Deflated +
- ((DeflaterConstants.MaxWbits - 8) << 4)) << 8;
- int levelFlags = (this.deflaterLevel - 1) >> 1;
- if (levelFlags < 0 || levelFlags > 3)
- {
- levelFlags = 3;
- }
-
- header |= levelFlags << 6;
- if ((this.state & IsSetdict) != 0)
- {
- // Dictionary was set
- header |= DeflaterConstants.PresetDict;
- }
-
- header += 31 - (header % 31);
-
- this.pending.WriteShortMSB(header);
- if ((this.state & IsSetdict) != 0)
- {
- int chksum = this.engine.Adler;
- this.engine.ResetAdler();
- this.pending.WriteShortMSB(chksum >> 16);
- this.pending.WriteShortMSB(chksum & 0xffff);
- }
-
- this.state = BusyState | (this.state & (IsFlushing | IsFinishing));
- }
-
- for (; ;)
- {
- int count = this.pending.Flush(output, offset, length);
- offset += count;
- this.totalOut += count;
- length -= count;
-
- if (length == 0 || this.state == FinishedState)
- {
- break;
- }
-
- if (!this.engine.Deflate((this.state & IsFlushing) != 0, (this.state & IsFinishing) != 0))
- {
- if (this.state == BusyState)
- {
- // We need more input now
- return origLength - length;
- }
- else if (this.state == FlushingState)
- {
- if (this.deflaterLevel != NoCompression)
- {
- /* We have to supply some lookahead. 8 bit lookahead
- * is needed by the zlib inflater, and we must fill
- * the next byte, so that all bits are flushed.
- */
- int neededbits = 8 + ((-this.pending.BitCount) & 7);
- while (neededbits > 0)
- {
- /* write a static tree block consisting solely of
- * an EOF:
- */
- this.pending.WriteBits(2, 10);
- neededbits -= 10;
- }
- }
-
- this.state = BusyState;
- }
- else if (this.state == FinishingState)
- {
- this.pending.AlignToByte();
-
- // Compressed data is complete. Write footer information if required.
- if (!this.noZlibHeaderOrFooter)
- {
- int adler = this.engine.Adler;
- this.pending.WriteShortMSB(adler >> 16);
- this.pending.WriteShortMSB(adler & 0xffff);
- }
-
- this.state = FinishedState;
- }
- }
- }
-
- return origLength - length;
- }
-
- ///
- /// Sets the dictionary which should be used in the deflate process.
- /// This call is equivalent to setDictionary(dict, 0, dict.Length).
- ///
- ///
- /// the dictionary.
- ///
- ///
- /// if SetInput () or Deflate () were already called or another dictionary was already set.
- ///
- public void SetDictionary(byte[] dictionary)
- {
- this.SetDictionary(dictionary, 0, dictionary.Length);
- }
-
- ///
- /// Sets the dictionary which should be used in the deflate process.
- /// The dictionary is a byte array containing strings that are
- /// likely to occur in the data which should be compressed. The
- /// dictionary is not stored in the compressed output, only a
- /// checksum. To decompress the output you need to supply the same
- /// dictionary again.
- ///
- ///
- /// The dictionary data
- ///
- ///
- /// The index where dictionary information commences.
- ///
- ///
- /// The number of bytes in the dictionary.
- ///
- ///
- /// If SetInput () or Deflate() were already called or another dictionary was already set.
- ///
- public void SetDictionary(byte[] dictionary, int index, int count)
- {
- if (this.state != InitState)
- {
- throw new InvalidOperationException();
- }
-
- this.state = SetdictState;
- this.engine.SetDictionary(dictionary, index, count);
- }
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/DeflaterConstants.cs b/src/ImageProcessor/Formats/Png/Zlib/DeflaterConstants.cs
deleted file mode 100644
index 8f333f5f6..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/DeflaterConstants.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageProcessor.Formats
-{
- using System;
-
- ///
- /// This class contains constants used for deflation.
- ///
- public class DeflaterConstants
- {
- ///
- /// Written to Zip file to identify a stored block
- ///
- public const int StoredBlock = 0;
-
- ///
- /// Identifies static tree in Zip file
- ///
- public const int StaticTrees = 1;
-
- ///
- /// Identifies dynamic tree in Zip file
- ///
- public const int DynTrees = 2;
-
- ///
- /// Header flag indicating a preset dictionary for deflation
- ///
- public const int PresetDict = 0x20;
-
- ///
- /// Sets internal buffer sizes for Huffman encoding
- ///
- public const int DefaultMemLevel = 8;
-
- ///
- /// Internal compression engine constant
- ///
- public const int MaxMatch = 258;
-
- ///
- /// Internal compression engine constant
- ///
- public const int MinMatch = 3;
-
- ///
- /// Internal compression engine constant
- ///
- public const int MaxWbits = 15;
-
- ///
- /// Internal compression engine constant
- ///
- public const int Wsize = 1 << MaxWbits;
-
- ///
- /// Internal compression engine constant
- ///
- public const int Wmask = Wsize - 1;
-
- ///
- /// Internal compression engine constant
- ///
- public const int HashBits = DefaultMemLevel + 7;
-
- ///
- /// Internal compression engine constant
- ///
- public const int HashSize = 1 << HashBits;
-
- ///
- /// Internal compression engine constant
- ///
- public const int HashMask = HashSize - 1;
-
- ///
- /// Internal compression engine constant
- ///
- public const int HashShift = (HashBits + MinMatch - 1) / MinMatch;
-
- ///
- /// Internal compression engine constant
- ///
- public const int MinLookahead = MaxMatch + MinMatch + 1;
-
- ///
- /// Internal compression engine constant
- ///
- public const int MaxDist = Wsize - MinLookahead;
-
- ///
- /// Internal compression engine constant
- ///
- public const int PendingBufSize = 1 << (DefaultMemLevel + 8);
-
- ///
- /// Internal compression engine constant
- ///
- public const int Deflatestored = 0;
-
- ///
- /// Internal compression engine constant
- ///
- public const int Deflatefast = 1;
-
- ///
- /// Internal compression engine constant
- ///
- public const int Deflateslow = 2;
-
- ///
- /// Internal compression engine constant
- ///
- public static int MaxBlockSize => Math.Min(65535, PendingBufSize - 5);
-
- ///
- /// Internal compression engine constant
- ///
- public static int[] GoodLength => new[] { 0, 4, 4, 4, 4, 8, 8, 8, 32, 32 };
-
- ///
- /// Internal compression engine constant
- ///
- public static int[] MaxLazy => new[] { 0, 4, 5, 6, 4, 16, 16, 32, 128, 258 };
-
- ///
- /// Internal compression engine constant
- ///
- public static int[] NiceLength => new[] { 0, 8, 16, 32, 16, 32, 128, 128, 258, 258 };
-
- ///
- /// Internal compression engine constant
- ///
- public static int[] MaxChain => new[] { 0, 4, 8, 32, 16, 32, 128, 256, 1024, 4096 };
-
- ///
- /// Internal compression engine constant
- ///
- public static int[] ComprFunc => new[] { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2 };
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/DeflaterEngine.cs b/src/ImageProcessor/Formats/Png/Zlib/DeflaterEngine.cs
deleted file mode 100644
index 1b5da2715..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/DeflaterEngine.cs
+++ /dev/null
@@ -1,810 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageProcessor.Formats
-{
- using System;
-
- ///
- /// Low level compression engine for deflate algorithm which uses a 32K sliding window
- /// with secondary compression from Huffman/Shannon-Fano codes.
- ///
- ///
- /// DEFLATE ALGORITHM:
- ///
- /// The uncompressed stream is inserted into the window array. When
- /// the window array is full the first half is thrown away and the
- /// second half is copied to the beginning.
- ///
- /// The head array is a hash table. Three characters build a hash value
- /// and they the value points to the corresponding index in window of
- /// the last string with this hash. The prev array implements a
- /// linked list of matches with the same hash: prev[index & WMASK] points
- /// to the previous index with the same hash.
- ///
- public class DeflaterEngine : DeflaterConstants
- {
- ///
- /// One more than the maximum upper bounds.
- ///
- private const int TooFar = 4096;
-
- ///
- /// prev[index & WMASK] points to the previous index that has the
- /// same hash code as the string starting at index. This way
- /// entries with the same hash code are in a linked list.
- /// Note that the array should really be unsigned short, so you need
- /// to and the values with 0xffff.
- ///
- private readonly short[] previousIndex;
-
- ///
- /// Hashtable, hashing three characters to an index for window, so
- /// that window[index]..window[index+2] have this hash code.
- /// Note that the array should really be unsigned short, so you need
- /// to and the values with 0xffff.
- ///
- private readonly short[] head;
-
- ///
- /// This array contains the part of the uncompressed stream that
- /// is of relevance. The current character is indexed by strstart.
- ///
- private readonly byte[] window;
-
- ///
- /// Stores the pending output of the deflator
- ///
- private readonly DeflaterPending pending;
-
- ///
- /// The huffman deflator
- ///
- private readonly DeflaterHuffman huffman;
-
- ///
- /// The adler checksum
- ///
- private readonly Adler32 adler;
-
- ///
- /// Hash index of string to be inserted.
- ///
- private int insertHashIndex;
-
- ///
- /// Index of the beginning of a match.
- ///
- private int matchStart;
-
- ///
- /// Length of best match
- ///
- private int matchLen;
-
- ///
- /// Set if previous match exists
- ///
- private bool prevAvailable;
-
- ///
- /// The index of the beinning of a block
- ///
- private int blockStart;
-
- ///
- /// Points to the current character in the window.
- ///
- private int strstart;
-
- ///
- /// lookahead is the number of characters starting at strstart in
- /// window that are valid.
- /// So window[strstart] until window[strstart+lookahead-1] are valid
- /// characters.
- ///
- private int lookahead;
-
- ///
- /// The maximum chain length
- ///
- private int maxChain;
-
- ///
- /// The maximum lazy length
- ///
- private int maxLazy;
-
- ///
- /// The nice length
- ///
- private int niceLength;
-
- ///
- /// The good length
- ///
- private int goodLength;
-
- ///
- /// The current compression function.
- ///
- private int compressionFunction;
-
- ///
- /// The input data for compression.
- ///
- private byte[] inputBuf;
-
- ///
- /// The total bytes of input read.
- ///
- private long totalIn;
-
- ///
- /// The offset into inputBuf, where input data starts.
- ///
- private int inputOff;
-
- ///
- /// The end offset of the input data.
- ///
- private int inputEnd;
-
- ///
- /// Initializes a new instance of the class with a pending buffer.
- ///
- /// The pending buffer to use>
- public DeflaterEngine(DeflaterPending pending)
- {
- this.pending = pending;
- this.huffman = new DeflaterHuffman(pending);
- this.adler = new Adler32();
-
- this.window = new byte[2 * Wsize];
- this.head = new short[HashSize];
- this.previousIndex = new short[Wsize];
-
- // We start at index 1, to avoid an implementation deficiency, that
- // we cannot build a repeat pattern at index 0.
- this.blockStart = this.strstart = 1;
- }
-
- ///
- /// Get current value of Adler checksum
- ///
- public int Adler => unchecked((int)this.adler.Value);
-
- ///
- /// Total data processed
- ///
- public long TotalIn => this.totalIn;
-
- ///
- /// Get or sets the
- ///
- public DeflateStrategy Strategy { get; set; }
-
- ///
- /// Deflate drives actual compression of data
- ///
- /// True to flush input buffers
- /// Finish deflation with the current input.
- /// Returns true if progress has been made.
- public bool Deflate(bool flush, bool finish)
- {
- bool progress;
- do
- {
- this.FillWindow();
- bool canFlush = flush && (this.inputOff == this.inputEnd);
-
- switch (this.compressionFunction)
- {
- case Deflatestored:
- progress = this.DeflateStored(canFlush, finish);
- break;
- case Deflatefast:
- progress = this.DeflateFast(canFlush, finish);
- break;
- case Deflateslow:
- progress = this.DeflateSlow(canFlush, finish);
- break;
- default:
- throw new InvalidOperationException("unknown compressionFunction");
- }
- }
- while (this.pending.IsFlushed && progress); // repeat while we have no pending output and progress was made
- return progress;
- }
-
- ///
- /// Sets input data to be deflated. Should only be called when NeedsInput()
- /// returns true
- ///
- /// The buffer containing input data.
- /// The offset of the first byte of data.
- /// The number of bytes of data to use as input.
- public void SetInput(byte[] buffer, int offset, int count)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
-
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(offset));
- }
-
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(count));
- }
-
- if (this.inputOff < this.inputEnd)
- {
- throw new InvalidOperationException("Old input was not completely processed");
- }
-
- int end = offset + count;
-
- // We want to throw an ArrayIndexOutOfBoundsException early. The
- // check is very tricky: it also handles integer wrap around.
- if ((offset > end) || (end > buffer.Length))
- {
- throw new ArgumentOutOfRangeException(nameof(count));
- }
-
- this.inputBuf = buffer;
- this.inputOff = offset;
- this.inputEnd = end;
- }
-
- ///
- /// Determines if more input is needed.
- ///
- /// Return true if input is needed via SetInput
- public bool NeedsInput()
- {
- return this.inputEnd == this.inputOff;
- }
-
- ///
- /// Set compression dictionary
- ///
- /// The buffer containing the dictionary data
- /// The offset in the buffer for the first byte of data
- /// The length of the dictionary data.
- public void SetDictionary(byte[] buffer, int offset, int length)
- {
- this.adler.Update(buffer, offset, length);
- if (length < MinMatch)
- {
- return;
- }
-
- if (length > MaxDist)
- {
- offset += length - MaxDist;
- length = MaxDist;
- }
-
- Array.Copy(buffer, offset, this.window, this.strstart, length);
-
- this.UpdateHash();
- --length;
- while (--length > 0)
- {
- this.InsertString();
- this.strstart++;
- }
-
- this.strstart += 2;
- this.blockStart = this.strstart;
- }
-
- ///
- /// Reset internal state
- ///
- public void Reset()
- {
- this.huffman.Reset();
- this.adler.Reset();
- this.blockStart = this.strstart = 1;
- this.lookahead = 0;
- this.totalIn = 0;
- this.prevAvailable = false;
- this.matchLen = MinMatch - 1;
-
- for (int i = 0; i < HashSize; i++)
- {
- this.head[i] = 0;
- }
-
- for (int i = 0; i < Wsize; i++)
- {
- this.previousIndex[i] = 0;
- }
- }
-
- ///
- /// Reset Adler checksum
- ///
- public void ResetAdler()
- {
- this.adler.Reset();
- }
-
- ///
- /// Set the deflate level (0-9)
- ///
- /// The value to set the level to.
- public void SetLevel(int level)
- {
- if ((level < 0) || (level > 9))
- {
- throw new ArgumentOutOfRangeException(nameof(level));
- }
-
- this.goodLength = GoodLength[level];
- this.maxLazy = MaxLazy[level];
- this.niceLength = NiceLength[level];
- this.maxChain = MaxChain[level];
-
- if (ComprFunc[level] != this.compressionFunction)
- {
- switch (this.compressionFunction)
- {
- case Deflatestored:
- if (this.strstart > this.blockStart)
- {
- this.huffman.FlushStoredBlock(this.window, this.blockStart, this.strstart - this.blockStart, false);
- this.blockStart = this.strstart;
- }
-
- this.UpdateHash();
- break;
-
- case Deflatefast:
- if (this.strstart > this.blockStart)
- {
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, false);
- this.blockStart = this.strstart;
- }
-
- break;
-
- case Deflateslow:
- if (this.prevAvailable)
- {
- this.huffman.TallyLit(this.window[this.strstart - 1] & 0xff);
- }
-
- if (this.strstart > this.blockStart)
- {
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, false);
- this.blockStart = this.strstart;
- }
-
- this.prevAvailable = false;
- this.matchLen = MinMatch - 1;
- break;
- }
-
- this.compressionFunction = ComprFunc[level];
- }
- }
-
- ///
- /// Fills the window
- ///
- public void FillWindow()
- {
- // If the window is almost full and there is insufficient lookahead,
- // move the upper half to the lower one to make room in the upper half.
- if (this.strstart >= Wsize + MaxDist)
- {
- this.SlideWindow();
- }
-
- // If there is not enough lookahead, but still some input left,
- // read in the input
- while (this.lookahead < MinLookahead && this.inputOff < this.inputEnd)
- {
- int more = (2 * Wsize) - this.lookahead - this.strstart;
-
- if (more > this.inputEnd - this.inputOff)
- {
- more = this.inputEnd - this.inputOff;
- }
-
- Array.Copy(this.inputBuf, this.inputOff, this.window, this.strstart + this.lookahead, more);
- this.adler.Update(this.inputBuf, this.inputOff, more);
-
- this.inputOff += more;
- this.totalIn += more;
- this.lookahead += more;
- }
-
- if (this.lookahead >= MinMatch)
- {
- this.UpdateHash();
- }
- }
-
- ///
- /// Updates this hash.
- ///
- private void UpdateHash()
- {
- this.insertHashIndex = (this.window[this.strstart] << HashShift) ^ this.window[this.strstart + 1];
- }
-
- ///
- /// Inserts the current string in the head hash and returns the previous
- /// value for this hash.
- ///
- /// The previous hash value
- private int InsertString()
- {
- short match;
- int hash = ((this.insertHashIndex << HashShift) ^ this.window[this.strstart + (MinMatch - 1)]) & HashMask;
-
- this.previousIndex[this.strstart & Wmask] = match = this.head[hash];
- this.head[hash] = unchecked((short)this.strstart);
- this.insertHashIndex = hash;
- return match & 0xffff;
- }
-
- ///
- /// Slides the current byte window to the ewlefvent part of the uncompressed stream.
- ///
- private void SlideWindow()
- {
- Array.Copy(this.window, Wsize, this.window, 0, Wsize);
- this.matchStart -= Wsize;
- this.strstart -= Wsize;
- this.blockStart -= Wsize;
-
- // Slide the hash table (could be avoided with 32 bit values
- // at the expense of memory usage).
- for (int i = 0; i < HashSize; ++i)
- {
- int m = this.head[i] & 0xffff;
- this.head[i] = (short)(m >= Wsize ? (m - Wsize) : 0);
- }
-
- // Slide the prev table.
- for (int i = 0; i < Wsize; i++)
- {
- int m = this.previousIndex[i] & 0xffff;
- this.previousIndex[i] = (short)(m >= Wsize ? (m - Wsize) : 0);
- }
- }
-
- ///
- /// Find the best (longest) string in the window matching the
- /// string starting at strstart.
- ///
- /// Preconditions:
- ///
- /// strstart + MAX_MATCH <= window.length.
- ///
- /// The current match.
- /// True if a match greater than the minimum length is found
- private bool FindLongestMatch(int curMatch)
- {
- int chainLength = this.maxChain;
- int length = this.niceLength;
- short[] previous = this.previousIndex;
- int scan = this.strstart;
- int bestEnd = this.strstart + this.matchLen;
- int bestLength = Math.Max(this.matchLen, MinMatch - 1);
-
- int limit = Math.Max(this.strstart - MaxDist, 0);
-
- int strend = this.strstart + MaxMatch - 1;
- byte scanEnd1 = this.window[bestEnd - 1];
- byte scanEnd = this.window[bestEnd];
-
- // Do not waste too much time if we already have a good match:
- if (bestLength >= this.goodLength)
- {
- chainLength >>= 2;
- }
-
- // Do not look for matches beyond the end of the input. This is necessary
- // to make deflate deterministic.
- if (length > this.lookahead)
- {
- length = this.lookahead;
- }
-
- do
- {
- if (this.window[curMatch + bestLength] != scanEnd ||
- this.window[curMatch + bestLength - 1] != scanEnd1 ||
- this.window[curMatch] != this.window[scan] ||
- this.window[curMatch + 1] != this.window[scan + 1])
- {
- continue;
- }
-
- int match = curMatch + 2;
- scan += 2;
-
- // We check for insufficient lookahead only every 8th comparison;
- // the 256th check will be made at strstart + 258.
- while (
- this.window[++scan] == this.window[++match] &&
- this.window[++scan] == this.window[++match] &&
- this.window[++scan] == this.window[++match] &&
- this.window[++scan] == this.window[++match] &&
- this.window[++scan] == this.window[++match] &&
- this.window[++scan] == this.window[++match] &&
- this.window[++scan] == this.window[++match] &&
- this.window[++scan] == this.window[++match] &&
- (scan < strend))
- {
- // Do nothing
- }
-
- if (scan > bestEnd)
- {
- this.matchStart = curMatch;
- bestEnd = scan;
- bestLength = scan - this.strstart;
-
- if (bestLength >= length)
- {
- break;
- }
-
- scanEnd1 = this.window[bestEnd - 1];
- scanEnd = this.window[bestEnd];
- }
-
- scan = this.strstart;
- }
- while ((curMatch = previous[curMatch & Wmask] & 0xffff) > limit && --chainLength != 0);
-
- this.matchLen = Math.Min(bestLength, this.lookahead);
- return this.matchLen >= MinMatch;
- }
-
- ///
- /// Returns a value indicating whether the uncompressed block is stored.
- ///
- /// Whether to flush the stream.
- /// Whether to finish the stream.
- /// The
- private bool DeflateStored(bool flush, bool finish)
- {
- if (!flush && (this.lookahead == 0))
- {
- return false;
- }
-
- this.strstart += this.lookahead;
- this.lookahead = 0;
-
- int storedLength = this.strstart - this.blockStart;
-
- if ((storedLength >= MaxBlockSize) || // Block is full
- (this.blockStart < Wsize && storedLength >= MaxDist) || // Block may move out of window
- flush)
- {
- bool lastBlock = finish;
- if (storedLength > MaxBlockSize)
- {
- storedLength = MaxBlockSize;
- lastBlock = false;
- }
-
- this.huffman.FlushStoredBlock(this.window, this.blockStart, storedLength, lastBlock);
- this.blockStart += storedLength;
- return !lastBlock;
- }
-
- return true;
- }
-
- ///
- /// Performs a fast deflation of the input stream return a value to indicate succes.
- ///
- /// Whether to flush the stream.
- /// Whether to finish the stream.
- /// The
- private bool DeflateFast(bool flush, bool finish)
- {
- if (this.lookahead < MinLookahead && !flush)
- {
- return false;
- }
-
- while (this.lookahead >= MinLookahead || flush)
- {
- if (this.lookahead == 0)
- {
- // We are flushing everything
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, finish);
- this.blockStart = this.strstart;
- return false;
- }
-
- if (this.strstart > (2 * Wsize) - MinLookahead)
- {
- // slide window, as FindLongestMatch needs this.
- // This should only happen when flushing and the window
- // is almost full.
- this.SlideWindow();
- }
-
- int hashHead;
- if (this.lookahead >= MinMatch &&
- (hashHead = this.InsertString()) != 0 &&
- this.Strategy != DeflateStrategy.HuffmanOnly &&
- this.strstart - hashHead <= MaxDist &&
- this.FindLongestMatch(hashHead))
- {
- // longestMatch sets matchStart and matchLen
- bool full = this.huffman.TallyDist(this.strstart - this.matchStart, this.matchLen);
-
- this.lookahead -= this.matchLen;
- if (this.matchLen <= this.maxLazy && this.lookahead >= MinMatch)
- {
- while (--this.matchLen > 0)
- {
- ++this.strstart;
- this.InsertString();
- }
-
- ++this.strstart;
- }
- else
- {
- this.strstart += this.matchLen;
- if (this.lookahead >= MinMatch - 1)
- {
- this.UpdateHash();
- }
- }
-
- this.matchLen = MinMatch - 1;
- if (!full)
- {
- continue;
- }
- }
- else
- {
- // No match found
- this.huffman.TallyLit(this.window[this.strstart] & 0xff);
- ++this.strstart;
- --this.lookahead;
- }
-
- if (this.huffman.IsFull())
- {
- bool lastBlock = finish && (this.lookahead == 0);
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, lastBlock);
- this.blockStart = this.strstart;
- return !lastBlock;
- }
- }
-
- return true;
- }
-
- ///
- /// Performs a slow deflation of the input stream return a value to indicate succes.
- ///
- /// Whether to flush the stream.
- /// Whether to finish the stream.
- /// The
- private bool DeflateSlow(bool flush, bool finish)
- {
- if (this.lookahead < MinLookahead && !flush)
- {
- return false;
- }
-
- while (this.lookahead >= MinLookahead || flush)
- {
- if (this.lookahead == 0)
- {
- if (this.prevAvailable)
- {
- this.huffman.TallyLit(this.window[this.strstart - 1] & 0xff);
- }
-
- this.prevAvailable = false;
-
- // We are flushing everything
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, finish);
- this.blockStart = this.strstart;
- return false;
- }
-
- if (this.strstart >= (2 * Wsize) - MinLookahead)
- {
- // slide window, as FindLongestMatch needs this.
- // This should only happen when flushing and the window
- // is almost full.
- this.SlideWindow();
- }
-
- int prevMatch = this.matchStart;
- int prevLen = this.matchLen;
- if (this.lookahead >= MinMatch)
- {
- int hashHead = this.InsertString();
-
- if (this.Strategy != DeflateStrategy.HuffmanOnly &&
- hashHead != 0 &&
- this.strstart - hashHead <= MaxDist &&
- this.FindLongestMatch(hashHead))
- {
- // longestMatch sets matchStart and matchLen
- // Discard match if too small and too far away
- if (this.matchLen <= 5 && (this.Strategy == DeflateStrategy.Filtered || (this.matchLen == MinMatch && this.strstart - this.matchStart > TooFar)))
- {
- this.matchLen = MinMatch - 1;
- }
- }
- }
-
- // previous match was better
- if ((prevLen >= MinMatch) && (this.matchLen <= prevLen))
- {
- this.huffman.TallyDist(this.strstart - 1 - prevMatch, prevLen);
- prevLen -= 2;
- do
- {
- this.strstart++;
- this.lookahead--;
- if (this.lookahead >= MinMatch)
- {
- this.InsertString();
- }
- }
- while (--prevLen > 0);
-
- this.strstart++;
- this.lookahead--;
- this.prevAvailable = false;
- this.matchLen = MinMatch - 1;
- }
- else
- {
- if (this.prevAvailable)
- {
- this.huffman.TallyLit(this.window[this.strstart - 1] & 0xff);
- }
-
- this.prevAvailable = true;
- this.strstart++;
- this.lookahead--;
- }
-
- if (this.huffman.IsFull())
- {
- int len = this.strstart - this.blockStart;
- if (this.prevAvailable)
- {
- len--;
- }
-
- bool lastBlock = finish && (this.lookahead == 0) && !this.prevAvailable;
- this.huffman.FlushBlock(this.window, this.blockStart, len, lastBlock);
- this.blockStart += len;
- return !lastBlock;
- }
- }
-
- return true;
- }
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/DeflaterHuffman.cs b/src/ImageProcessor/Formats/Png/Zlib/DeflaterHuffman.cs
deleted file mode 100644
index 5d6857d41..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/DeflaterHuffman.cs
+++ /dev/null
@@ -1,889 +0,0 @@
-namespace ImageProcessor.Formats
-{
- using System;
-
- ///
- /// This is the DeflaterHuffman class.
- ///
- /// This class is not thread safe. This is inherent in the API, due
- /// to the split of Deflate and SetInput.
- ///
- /// author of the original java version : Jochen Hoenicke
- ///
- public class DeflaterHuffman
- {
- ///
- /// The buffer size.
- ///
- private const int Buffersize = 1 << (DeflaterConstants.DefaultMemLevel + 6);
-
- ///
- /// The number of literals.
- ///
- private const int LiteralCount = 286;
-
- ///
- /// Number of distance codes
- ///
- private const int DistanceCodeCount = 30;
-
- ///
- /// Number of codes used to transfer bit lengths
- ///
- private const int BitLengthCount = 19;
-
- ///
- /// Repeat previous bit length 3-6 times (2 bits of repeat count)
- ///
- private const int Repeat3To6 = 16;
-
- ///
- /// Repeat a zero length 3-10 times (3 bits of repeat count)
- ///
- private const int Repeat3To10 = 17;
-
- ///
- /// Repeat a zero length 11-138 times (7 bits of repeat count)
- ///
- private const int Repeat11To138 = 18;
-
- ///
- /// The end of file flag.
- ///
- private const int Eof = 256;
-
- ///
- /// The lengths of the bit length codes are sent in order of decreasing
- /// probability, to avoid transmitting the lengths for unused bit length codes.
- ///
- private static readonly int[] BitLengthOrder = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
-
- ///
- /// Bit data reversed.
- ///
- private static readonly byte[] Bit4Reverse = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
-
- ///
- /// The literal codes.
- ///
- private static short[] staticLCodes;
- private static byte[] staticLLength;
- private static short[] staticDCodes;
- private static byte[] staticDLength;
-
- ///
- /// A binary tree, with the property, that the parent node is smaller than both child nodes.
- ///
- private class Tree
- {
- ///
- /// The minimum number of codes.
- ///
- private readonly int minimumNumberOfCodes;
-
- ///
- /// The array of codes.
- ///
- private short[] codes;
- private readonly int[] blCounts;
- private readonly int maxLength;
- private readonly DeflaterHuffman deflater;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The
- /// The elements.
- /// The minimum number of codes.
- /// The maximum length.
- public Tree(DeflaterHuffman huffman, int elems, int minCodes, int maxLength)
- {
- this.deflater = huffman;
- this.minimumNumberOfCodes = minCodes;
- this.maxLength = maxLength;
- this.Frequencies = new short[elems];
- this.blCounts = new int[maxLength];
- }
-
- ///
- /// Gets the number of codes.
- ///
- public int NumberOfCodes { get; private set; }
-
- ///
- /// Gets the frequencies.
- ///
- public short[] Frequencies { get; }
-
- ///
- /// Gets or sets the length.
- ///
- public byte[] Length { get; private set; }
-
- ///
- /// Resets the internal state of the tree
- ///
- public void Reset()
- {
- for (int i = 0; i < this.Frequencies.Length; i++)
- {
- this.Frequencies[i] = 0;
- }
-
- this.codes = null;
- this.Length = null;
- }
-
- ///
- /// Writes a code symbol.
- ///
- /// The code index.
- public void WriteSymbol(int code)
- {
- this.deflater.pending.WriteBits(this.codes[code] & 0xffff, this.Length[code]);
- }
-
- ///
- /// Set static codes and length
- ///
- /// new codes
- /// length for new codes
- public void SetStaticCodes(short[] staticCodes, byte[] staticLengths)
- {
- this.codes = staticCodes;
- this.Length = staticLengths;
- }
-
- ///
- /// Build dynamic codes and lengths
- ///
- public void BuildCodes()
- {
- int numSymbols = this.Frequencies.Length;
- int[] nextCode = new int[this.maxLength];
- int code = 0;
-
- this.codes = new short[numSymbols];
-
- for (int bits = 0; bits < this.maxLength; bits++)
- {
- nextCode[bits] = code;
- code += this.blCounts[bits] << (15 - bits);
- }
-
- for (int i = 0; i < this.NumberOfCodes; i++)
- {
- int bits = this.Length[i];
- if (bits > 0)
- {
- this.codes[i] = BitReverse(nextCode[bits - 1]);
- nextCode[bits - 1] += 1 << (16 - bits);
- }
- }
- }
-
- public void BuildTree()
- {
- int numSymbols = this.Frequencies.Length;
-
- // Heap is a priority queue, sorted by frequency, least frequent
- // nodes first. The heap is a binary tree, with the property, that
- // the parent node is smaller than both child nodes. This assures
- // that the smallest node is the first parent.
- //
- // The binary tree is encoded in an array: 0 is root node and
- // the nodes 2//n+1, 2//n+2 are the child nodes of node n.
- int[] heap = new int[numSymbols];
- int heapLen = 0;
- int maxCode = 0;
- for (int n = 0; n < numSymbols; n++)
- {
- int freq = this.Frequencies[n];
- if (freq != 0)
- {
- // Insert n into heap
- int pos = heapLen++;
- int ppos;
- while (pos > 0 && this.Frequencies[heap[ppos = (pos - 1) / 2]] > freq)
- {
- heap[pos] = heap[ppos];
- pos = ppos;
- }
-
- heap[pos] = n;
-
- maxCode = n;
- }
- }
-
- // We could encode a single literal with 0 bits but then we
- // don't see the literals. Therefore we force at least two
- // literals to avoid this case. We don't care about order in
- // this case, both literals get a 1 bit code.
- while (heapLen < 2)
- {
- int node = maxCode < 2 ? ++maxCode : 0;
- heap[heapLen++] = node;
- }
-
- this.NumberOfCodes = Math.Max(maxCode + 1, this.minimumNumberOfCodes);
-
- int numLeafs = heapLen;
- int[] childs = new int[(4 * heapLen) - 2];
- int[] values = new int[(2 * heapLen) - 1];
- int numNodes = numLeafs;
- for (int i = 0; i < heapLen; i++)
- {
- int node = heap[i];
- childs[2 * i] = node;
- childs[(2 * i) + 1] = -1;
- values[i] = this.Frequencies[node] << 8;
- heap[i] = i;
- }
-
- // Construct the Huffman tree by repeatedly combining the least two
- // frequent nodes.
- do
- {
- int first = heap[0];
- int last = heap[--heapLen];
-
- // Propagate the hole to the leafs of the heap
- int ppos = 0;
- int path = 1;
-
- while (path < heapLen)
- {
- if (path + 1 < heapLen && values[heap[path]] > values[heap[path + 1]])
- {
- path++;
- }
-
- heap[ppos] = heap[path];
- ppos = path;
- path = (path * 2) + 1;
- }
-
- // Now propagate the last element down along path. Normally
- // it shouldn't go too deep.
- int lastVal = values[last];
- while ((path = ppos) > 0 && values[heap[ppos = (path - 1) / 2]] > lastVal)
- {
- heap[path] = heap[ppos];
- }
-
- heap[path] = last;
-
- int second = heap[0];
-
- // Create a new node father of first and second
- last = numNodes++;
- childs[2 * last] = first;
- childs[(2 * last) + 1] = second;
- int mindepth = Math.Min(values[first] & 0xff, values[second] & 0xff);
- values[last] = lastVal = values[first] + values[second] - mindepth + 1;
-
- // Again, propagate the hole to the leafs
- ppos = 0;
- path = 1;
-
- while (path < heapLen)
- {
- if (path + 1 < heapLen && values[heap[path]] > values[heap[path + 1]])
- {
- path++;
- }
-
- heap[ppos] = heap[path];
- ppos = path;
- path = (ppos * 2) + 1;
- }
-
- // Now propagate the new element down along path
- while ((path = ppos) > 0 && values[heap[ppos = (path - 1) / 2]] > lastVal)
- {
- heap[path] = heap[ppos];
- }
-
- heap[path] = last;
- }
- while (heapLen > 1);
-
- if (heap[0] != (childs.Length / 2) - 1)
- {
- throw new ImageFormatException("Heap invariant violated");
- }
-
- this.BuildLength(childs);
- }
-
- ///
- /// Get encoded length
- ///
- /// Encoded length, the sum of frequencies * lengths
- public int GetEncodedLength()
- {
- int len = 0;
- for (int i = 0; i < this.Frequencies.Length; i++)
- {
- len += this.Frequencies[i] * this.Length[i];
- }
-
- return len;
- }
-
- ///
- /// Scan a literal or distance tree to determine the frequencies of the codes
- /// in the bit length tree.
- ///
- public void CalcBLFreq(Tree blTree)
- {
- int max_count; /* max repeat count */
- int min_count; /* min repeat count */
- int count; /* repeat count of the current code */
- int curlen = -1; /* length of current code */
-
- int i = 0;
- while (i < this.NumberOfCodes)
- {
- count = 1;
- int nextlen = this.Length[i];
- if (nextlen == 0)
- {
- max_count = 138;
- min_count = 3;
- }
- else
- {
- max_count = 6;
- min_count = 3;
- if (curlen != nextlen)
- {
- blTree.Frequencies[nextlen]++;
- count = 0;
- }
- }
-
- curlen = nextlen;
- i++;
-
- while (i < this.NumberOfCodes && curlen == this.Length[i])
- {
- i++;
- if (++count >= max_count)
- {
- break;
- }
- }
-
- if (count < min_count)
- {
- blTree.Frequencies[curlen] += (short)count;
- }
- else if (curlen != 0)
- {
- blTree.Frequencies[Repeat3To6]++;
- }
- else if (count <= 10)
- {
- blTree.Frequencies[Repeat3To10]++;
- }
- else
- {
- blTree.Frequencies[Repeat11To138]++;
- }
- }
- }
-
- ///
- /// Write tree values
- ///
- /// Tree to write
- public void WriteTree(Tree blTree)
- {
- int max_count; // max repeat count
- int min_count; // min repeat count
- int count; // repeat count of the current code
- int curlen = -1; // length of current code
-
- int i = 0;
- while (i < this.NumberOfCodes)
- {
- count = 1;
- int nextlen = this.Length[i];
- if (nextlen == 0)
- {
- max_count = 138;
- min_count = 3;
- }
- else
- {
- max_count = 6;
- min_count = 3;
- if (curlen != nextlen)
- {
- blTree.WriteSymbol(nextlen);
- count = 0;
- }
- }
-
- curlen = nextlen;
- i++;
-
- while (i < this.NumberOfCodes && curlen == this.Length[i])
- {
- i++;
- if (++count >= max_count)
- {
- break;
- }
- }
-
- if (count < min_count)
- {
- while (count-- > 0)
- {
- blTree.WriteSymbol(curlen);
- }
- }
- else if (curlen != 0)
- {
- blTree.WriteSymbol(Repeat3To6);
- this.deflater.pending.WriteBits(count - 3, 2);
- }
- else if (count <= 10)
- {
- blTree.WriteSymbol(Repeat3To10);
- this.deflater.pending.WriteBits(count - 3, 3);
- }
- else
- {
- blTree.WriteSymbol(Repeat11To138);
- this.deflater.pending.WriteBits(count - 11, 7);
- }
- }
- }
-
- private void BuildLength(int[] childs)
- {
- this.Length = new byte[this.Frequencies.Length];
- int numNodes = childs.Length / 2;
- int numLeafs = (numNodes + 1) / 2;
- int overflow = 0;
-
- for (int i = 0; i < this.maxLength; i++)
- {
- this.blCounts[i] = 0;
- }
-
- // First calculate optimal bit lengths
- int[] lengths = new int[numNodes];
- lengths[numNodes - 1] = 0;
-
- for (int i = numNodes - 1; i >= 0; i--)
- {
- if (childs[(2 * i) + 1] != -1)
- {
- int bitLength = lengths[i] + 1;
- if (bitLength > this.maxLength)
- {
- bitLength = this.maxLength;
- overflow++;
- }
-
- lengths[childs[2 * i]] = lengths[childs[(2 * i) + 1]] = bitLength;
- }
- else
- {
- // A leaf node
- int bitLength = lengths[i];
- this.blCounts[bitLength - 1]++;
- this.Length[childs[2 * i]] = (byte)lengths[i];
- }
- }
-
- if (overflow == 0)
- {
- return;
- }
-
- int incrBitLen = this.maxLength - 1;
- do
- {
- // Find the first bit length which could increase:
- while (this.blCounts[--incrBitLen] == 0)
- {
- }
-
- // Move this node one down and remove a corresponding
- // number of overflow nodes.
- do
- {
- this.blCounts[incrBitLen]--;
- this.blCounts[++incrBitLen]++;
- overflow -= 1 << (this.maxLength - 1 - incrBitLen);
- }
- while (overflow > 0 && incrBitLen < this.maxLength - 1);
- }
- while (overflow > 0);
-
- // We may have overshot above. Move some nodes from maxLength to
- // maxLength-1 in that case.
- this.blCounts[this.maxLength - 1] += overflow;
- this.blCounts[this.maxLength - 2] -= overflow;
-
- // Now recompute all bit lengths, scanning in increasing
- // frequency. It is simpler to reconstruct all lengths instead of
- // fixing only the wrong ones. This idea is taken from 'ar'
- // written by Haruhiko Okumura.
- // The nodes were inserted with decreasing frequency into the childs
- // array.
- int nodePtr = 2 * numLeafs;
- for (int bits = this.maxLength; bits != 0; bits--)
- {
- int n = this.blCounts[bits - 1];
- while (n > 0)
- {
- int childPtr = 2 * childs[nodePtr++];
- if (childs[childPtr + 1] == -1)
- {
- // We found another leaf
- this.Length[childs[childPtr]] = (byte)bits;
- n--;
- }
- }
- }
- }
- }
-
- ///
- /// Pending buffer to use
- ///
- public DeflaterPending pending;
-
- Tree literalTree;
- Tree distTree;
- Tree blTree;
-
- // Buffer for distances
- short[] d_buf;
- byte[] l_buf;
- int last_lit;
- int extra_bits;
-
- static DeflaterHuffman()
- {
- // See RFC 1951 3.2.6
- // Literal codes
- staticLCodes = new short[LiteralCount];
- staticLLength = new byte[LiteralCount];
-
- int i = 0;
- while (i < 144)
- {
- staticLCodes[i] = BitReverse((0x030 + i) << 8);
- staticLLength[i++] = 8;
- }
-
- while (i < 256)
- {
- staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7);
- staticLLength[i++] = 9;
- }
-
- while (i < 280)
- {
- staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9);
- staticLLength[i++] = 7;
- }
-
- while (i < LiteralCount)
- {
- staticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8);
- staticLLength[i++] = 8;
- }
-
- // Distance codes
- staticDCodes = new short[DistanceCodeCount];
- staticDLength = new byte[DistanceCodeCount];
- for (i = 0; i < DistanceCodeCount; i++)
- {
- staticDCodes[i] = BitReverse(i << 11);
- staticDLength[i] = 5;
- }
- }
-
- ///
- /// Initializes a new instance of the class with a pending buffer.
- ///
- /// Pending buffer to use
- public DeflaterHuffman(DeflaterPending pending)
- {
- this.pending = pending;
-
- this.literalTree = new Tree(this, LiteralCount, 257, 15);
- this.distTree = new Tree(this, DistanceCodeCount, 1, 15);
- this.blTree = new Tree(this, BitLengthCount, 4, 7);
-
- this.d_buf = new short[Buffersize];
- this.l_buf = new byte[Buffersize];
- }
-
- ///
- /// Reverse the bits of a 16 bit value.
- ///
- /// Value to reverse bits
- /// Value with bits reversed
- public static short BitReverse(int toReverse)
- {
- return (short)(Bit4Reverse[toReverse & 0xF] << 12 |
- Bit4Reverse[(toReverse >> 4) & 0xF] << 8 |
- Bit4Reverse[(toReverse >> 8) & 0xF] << 4 |
- Bit4Reverse[toReverse >> 12]);
- }
-
- ///
- /// Resets the internal state
- ///
- public void Reset()
- {
- this.last_lit = 0;
- this.extra_bits = 0;
- this.literalTree.Reset();
- this.distTree.Reset();
- this.blTree.Reset();
- }
-
- ///
- /// Write all trees to pending buffer
- ///
- /// The number/rank of treecodes to send.
- public void SendAllTrees(int blTreeCodes)
- {
- this.blTree.BuildCodes();
- this.literalTree.BuildCodes();
- this.distTree.BuildCodes();
- this.pending.WriteBits(this.literalTree.NumberOfCodes - 257, 5);
- this.pending.WriteBits(this.distTree.NumberOfCodes - 1, 5);
- this.pending.WriteBits(blTreeCodes - 4, 4);
-
- for (int rank = 0; rank < blTreeCodes; rank++)
- {
- this.pending.WriteBits(this.blTree.Length[BitLengthOrder[rank]], 3);
- }
-
- this.literalTree.WriteTree(this.blTree);
- this.distTree.WriteTree(this.blTree);
- }
-
- ///
- /// Compress current buffer writing data to pending buffer
- ///
- public void CompressBlock()
- {
- for (int i = 0; i < this.last_lit; i++)
- {
- int litlen = this.l_buf[i] & 0xff;
- int dist = this.d_buf[i];
- if (dist-- != 0)
- {
- int lc = Lcode(litlen);
- this.literalTree.WriteSymbol(lc);
-
- int bits = (lc - 261) / 4;
- if (bits > 0 && bits <= 5)
- {
- this.pending.WriteBits(litlen & ((1 << bits) - 1), bits);
- }
-
- int dc = Dcode(dist);
- this.distTree.WriteSymbol(dc);
-
- bits = (dc / 2) - 1;
- if (bits > 0)
- {
- this.pending.WriteBits(dist & ((1 << bits) - 1), bits);
- }
- }
- else
- {
- this.literalTree.WriteSymbol(litlen);
- }
- }
-
- this.literalTree.WriteSymbol(Eof);
- }
-
- ///
- /// Flush block to output with no compression
- ///
- /// Data to write
- /// Index of first byte to write
- /// Count of bytes to write
- /// True if this is the last block
- public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
- {
- this.pending.WriteBits((DeflaterConstants.StoredBlock << 1) + (lastBlock ? 1 : 0), 3);
- this.pending.AlignToByte();
- this.pending.WriteShort(storedLength);
- this.pending.WriteShort(~storedLength);
- this.pending.WriteBlock(stored, storedOffset, storedLength);
- this.Reset();
- }
-
- ///
- /// Flush block to output with compression
- ///
- /// Data to flush
- /// Index of first byte to flush
- /// Count of bytes to flush
- /// True if this is the last block
- public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
- {
- this.literalTree.Frequencies[Eof]++;
-
- // Build trees
- this.literalTree.BuildTree();
- this.distTree.BuildTree();
-
- // Calculate bitlen frequency
- this.literalTree.CalcBLFreq(this.blTree);
- this.distTree.CalcBLFreq(this.blTree);
-
- // Build bitlen tree
- this.blTree.BuildTree();
-
- int blTreeCodes = 4;
- for (int i = 18; i > blTreeCodes; i--)
- {
- if (this.blTree.Length[BitLengthOrder[i]] > 0)
- {
- blTreeCodes = i + 1;
- }
- }
-
- int opt_len = 14 + (blTreeCodes * 3) + this.blTree.GetEncodedLength() +
- this.literalTree.GetEncodedLength() + this.distTree.GetEncodedLength() +
- this.extra_bits;
-
- int static_len = this.extra_bits;
- for (int i = 0; i < LiteralCount; i++)
- {
- static_len += this.literalTree.Frequencies[i] * staticLLength[i];
- }
-
- for (int i = 0; i < DistanceCodeCount; i++)
- {
- static_len += this.distTree.Frequencies[i] * staticDLength[i];
- }
-
- if (opt_len >= static_len)
- {
- // Force static trees
- opt_len = static_len;
- }
-
- if (storedOffset >= 0 && storedLength + 4 < opt_len >> 3)
- {
- // Store Block
- this.FlushStoredBlock(stored, storedOffset, storedLength, lastBlock);
- }
- else if (opt_len == static_len)
- {
- // Encode with static tree
- this.pending.WriteBits((DeflaterConstants.StaticTrees << 1) + (lastBlock ? 1 : 0), 3);
- this.literalTree.SetStaticCodes(staticLCodes, staticLLength);
- this.distTree.SetStaticCodes(staticDCodes, staticDLength);
- this.CompressBlock();
- this.Reset();
- }
- else
- {
- // Encode with dynamic tree
- this.pending.WriteBits((DeflaterConstants.DynTrees << 1) + (lastBlock ? 1 : 0), 3);
- this.SendAllTrees(blTreeCodes);
- this.CompressBlock();
- this.Reset();
- }
- }
-
- ///
- /// Get value indicating if internal buffer is full
- ///
- /// true if buffer is full
- public bool IsFull()
- {
- return this.last_lit >= Buffersize;
- }
-
- ///
- /// Add literal to buffer
- ///
- /// Literal value to add to buffer.
- /// Value indicating internal buffer is full
- public bool TallyLit(int literal)
- {
- this.d_buf[this.last_lit] = 0;
- this.l_buf[this.last_lit++] = (byte)literal;
- this.literalTree.Frequencies[literal]++;
- return this.IsFull();
- }
-
- ///
- /// Add distance code and length to literal and distance trees
- ///
- /// Distance code
- /// Length
- /// Value indicating if internal buffer is full
- public bool TallyDist(int distance, int length)
- {
- this.d_buf[this.last_lit] = (short)distance;
- this.l_buf[this.last_lit++] = (byte)(length - 3);
-
- int lc = Lcode(length - 3);
- this.literalTree.Frequencies[lc]++;
- if (lc >= 265 && lc < 285)
- {
- this.extra_bits += (lc - 261) / 4;
- }
-
- int dc = Dcode(distance - 1);
- this.distTree.Frequencies[dc]++;
- if (dc >= 4)
- {
- this.extra_bits += (dc / 2) - 1;
- }
-
- return this.IsFull();
- }
-
- private static int Lcode(int length)
- {
- if (length == 255)
- {
- return 285;
- }
-
- int code = 257;
- while (length >= 8)
- {
- code += 4;
- length >>= 1;
- }
-
- return code + length;
- }
-
- private static int Dcode(int distance)
- {
- int code = 0;
- while (distance >= 4)
- {
- code += 2;
- distance >>= 1;
- }
-
- return code + distance;
- }
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/DeflaterOutputStream.cs b/src/ImageProcessor/Formats/Png/Zlib/DeflaterOutputStream.cs
deleted file mode 100644
index fad471025..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/DeflaterOutputStream.cs
+++ /dev/null
@@ -1,446 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageProcessor.Formats
-{
- using System;
- using System.IO;
-
- ///
- /// A special stream deflating or compressing the bytes that are
- /// written to it. It uses a Deflater to perform actual deflating.
- /// Authors of the original java version : Tom Tromey, Jochen Hoenicke
- ///
- public class DeflaterOutputStream : Stream
- {
- ///
- /// The deflater which is used to deflate the stream.
- ///
- private readonly Deflater deflater;
-
- ///
- /// Base stream the deflater depends on.
- ///
- private readonly Stream baseOutputStream;
-
- ///
- /// This buffer is used temporarily to retrieve the bytes from the
- /// deflater and write them to the underlying output stream.
- ///
- private readonly byte[] bytebuffer;
-
- ///
- /// The password
- ///
- private string password;
-
- ///
- /// The keys
- ///
- private uint[] keys;
-
- ///
- /// Whether the stream is closed
- ///
- private bool isClosed;
-
- ///
- /// Whether dispose should close the underlying stream.
- ///
- private bool isStreamOwner = true;
-
- ///
- /// Initializes a new instance of the class
- /// with a default Deflater and default buffer size.
- ///
- ///
- /// the output stream where deflated output should be written.
- ///
- public DeflaterOutputStream(Stream baseOutputStream)
- : this(baseOutputStream, new Deflater(), 512)
- {
- }
-
- ///
- /// Initializes a new instance of the class
- /// with the given Deflater and default buffer size.
- ///
- ///
- /// the output stream where deflated output should be written.
- ///
- ///
- /// the underlying deflater.
- ///
- public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater)
- : this(baseOutputStream, deflater, 512)
- {
- }
-
- ///
- /// Initializes a new instance of the class
- /// with the given Deflater and buffer size.
- ///
- ///
- /// The output stream where deflated output is written.
- ///
- ///
- /// The underlying deflater to use
- ///
- ///
- /// The buffer size in bytes to use when deflating (minimum value 512)
- ///
- /// buffersize is less than or equal to zero.
- /// baseOutputStream does not support writing.
- /// deflater instance is null.
- public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater, int bufferSize)
- {
- if (baseOutputStream == null)
- {
- throw new ArgumentNullException(nameof(baseOutputStream));
- }
-
- if (baseOutputStream.CanWrite == false)
- {
- throw new ArgumentException("Must support writing", nameof(baseOutputStream));
- }
-
- if (deflater == null)
- {
- throw new ArgumentNullException(nameof(deflater));
- }
-
- if (bufferSize < 512)
- {
- throw new ArgumentOutOfRangeException(nameof(bufferSize));
- }
-
- this.baseOutputStream = baseOutputStream;
- this.bytebuffer = new byte[bufferSize];
- this.deflater = deflater;
- }
-
- ///
- /// Get/set flag indicating ownership of the underlying stream.
- /// When the flag is true will close the underlying stream also.
- ///
- public bool IsStreamOwner
- {
- get { return this.isStreamOwner; }
- set { this.isStreamOwner = value; }
- }
-
- ///
- /// Allows client to determine if an entry can be patched after its added
- ///
- public bool CanPatchEntries => this.baseOutputStream.CanSeek;
-
- ///
- /// Get/set the password used for encryption.
- ///
- /// When set to null or if the password is empty no encryption is performed
- public string Password
- {
- get
- {
- return this.password;
- }
-
- set
- {
- if ((value != null) && (value.Length == 0))
- {
- this.password = null;
- }
- else
- {
- this.password = value;
- }
- }
- }
-
- ///
- /// Gets value indicating stream can be read from
- ///
- public override bool CanRead => false;
-
- ///
- /// Gets a value indicating if seeking is supported for this stream
- /// This property always returns false
- ///
- public override bool CanSeek => false;
-
- ///
- /// Get value indicating if this stream supports writing
- ///
- public override bool CanWrite => this.baseOutputStream.CanWrite;
-
- ///
- /// Get current length of stream
- ///
- public override long Length => this.baseOutputStream.Length;
-
- ///
- /// Gets the current position within the stream.
- ///
- /// Any attempt to set position
- public override long Position
- {
- get
- {
- return this.baseOutputStream.Position;
- }
-
- set
- {
- throw new NotSupportedException("Position property not supported");
- }
- }
-
- ///
- /// Finishes the stream by calling finish() on the deflater.
- ///
- ///
- /// Not all input is deflated
- ///
- public virtual void Finish()
- {
- this.deflater.Finish();
- while (!this.deflater.IsFinished)
- {
- int len = this.deflater.Deflate(this.bytebuffer, 0, this.bytebuffer.Length);
- if (len <= 0)
- {
- break;
- }
-
- if (this.keys != null)
- {
- this.EncryptBlock(this.bytebuffer, 0, len);
- }
-
- this.baseOutputStream.Write(this.bytebuffer, 0, len);
- }
-
- if (!this.deflater.IsFinished)
- {
- throw new ImageFormatException("Can't deflate all input?");
- }
-
- this.baseOutputStream.Flush();
- this.keys = null;
- }
-
- ///
- /// Sets the current position of this stream to the given value. Not supported by this class!
- ///
- /// The offset relative to the to seek.
- /// The to seek from.
- /// The new position in the stream.
- /// Any access
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotSupportedException("DeflaterOutputStream Seek not supported");
- }
-
- ///
- /// Sets the length of this stream to the given value. Not supported by this class!
- ///
- /// The new stream length.
- /// Any access
- public override void SetLength(long value)
- {
- throw new NotSupportedException("DeflaterOutputStream SetLength not supported");
- }
-
- ///
- /// Read a byte from stream advancing position by one
- ///
- /// The byte read cast to an int. THe value is -1 if at the end of the stream.
- /// Any access
- public override int ReadByte()
- {
- throw new NotSupportedException("DeflaterOutputStream ReadByte not supported");
- }
-
- ///
- /// Read a block of bytes from stream
- ///
- /// The buffer to store read data in.
- /// The offset to start storing at.
- /// The maximum number of bytes to read.
- /// The actual number of bytes read. Zero if end of stream is detected.
- /// Any access
- public override int Read(byte[] buffer, int offset, int count)
- {
- throw new NotSupportedException("DeflaterOutputStream Read not supported");
- }
-
- ///
- /// Flushes the stream by calling Flush on the deflater and then
- /// on the underlying stream. This ensures that all bytes are flushed.
- ///
- public override void Flush()
- {
- this.deflater.Flush();
- this.Deflate();
- this.baseOutputStream.Flush();
- }
-
- ///
- /// Writes a single byte to the compressed output stream.
- ///
- ///
- /// The byte value.
- ///
- public override void WriteByte(byte value)
- {
- byte[] b = new byte[1];
- b[0] = value;
- this.Write(b, 0, 1);
- }
-
- ///
- /// Writes bytes from an array to the compressed stream.
- ///
- ///
- /// The byte array
- ///
- ///
- /// The offset into the byte array where to start.
- ///
- ///
- /// The number of bytes to write.
- ///
- public override void Write(byte[] buffer, int offset, int count)
- {
- this.deflater.SetInput(buffer, offset, count);
- this.Deflate();
- }
-
- ///
- /// Encrypt a block of data
- ///
- ///
- /// Data to encrypt. NOTE the original contents of the buffer are lost
- ///
- ///
- /// Offset of first byte in buffer to encrypt
- ///
- ///
- /// Number of bytes in buffer to encrypt
- ///
- protected void EncryptBlock(byte[] buffer, int offset, int length)
- {
- for (int i = offset; i < offset + length; ++i)
- {
- byte oldbyte = buffer[i];
- buffer[i] ^= this.EncryptByte();
- this.UpdateKeys(oldbyte);
- }
- }
-
- ///
- /// Initializes encryption keys based on given .
- ///
- /// The password.
- protected void InitializePassword(string pssword)
- {
- this.keys = new uint[]
- {
- 0x12345678,
- 0x23456789,
- 0x34567890
- };
-
- byte[] rawPassword = ZipConstants.ConvertToArray(pssword);
-
- foreach (byte b in rawPassword)
- {
- this.UpdateKeys(b);
- }
- }
-
- ///
- /// Encrypt a single byte
- ///
- ///
- /// The encrypted value
- ///
- protected byte EncryptByte()
- {
- uint temp = (this.keys[2] & 0xFFFF) | 2;
- return (byte)((temp * (temp ^ 1)) >> 8);
- }
-
- ///
- /// Update encryption keys
- ///
- /// The character.
- protected void UpdateKeys(byte ch)
- {
- this.keys[0] = Crc32.ComputeCrc32(this.keys[0], ch);
- this.keys[1] = this.keys[1] + (byte)this.keys[0];
- this.keys[1] = (this.keys[1] * 134775813) + 1;
- this.keys[2] = Crc32.ComputeCrc32(this.keys[2], (byte)(this.keys[1] >> 24));
- }
-
- ///
- /// Deflates everything in the input buffers. This will call
- /// def.deflate() until all bytes from the input buffers
- /// are processed.
- ///
- protected void Deflate()
- {
- while (!this.deflater.IsNeedingInput)
- {
- int deflateCount = this.deflater.Deflate(this.bytebuffer, 0, this.bytebuffer.Length);
-
- if (deflateCount <= 0)
- {
- break;
- }
-
- if (this.keys != null)
- {
- this.EncryptBlock(this.bytebuffer, 0, deflateCount);
- }
-
- this.baseOutputStream.Write(this.bytebuffer, 0, deflateCount);
- }
-
- if (!this.deflater.IsNeedingInput)
- {
- throw new ImageFormatException("DeflaterOutputStream can't deflate all input?");
- }
- }
-
- ///
- /// Calls and closes the underlying
- /// stream when is true.
- ///
- /// If true, the object gets disposed.
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
- if (disposing && !this.isClosed)
- {
- this.isClosed = true;
-
- try
- {
- this.Finish();
- this.keys = null;
- }
- finally
- {
- if (this.isStreamOwner)
- {
- this.baseOutputStream.Dispose();
- }
- }
- }
- }
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/DeflaterPending.cs b/src/ImageProcessor/Formats/Png/Zlib/DeflaterPending.cs
deleted file mode 100644
index 67912bc30..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/DeflaterPending.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageProcessor.Formats
-{
- ///
- /// This class stores the pending output of the Deflater.
- ///
- /// author of the original java version : Jochen Hoenicke
- ///
- public class DeflaterPending : PendingBuffer
- {
- ///
- /// Initializes a new instance of the class.
- /// Construct instance with default buffer size
- ///
- public DeflaterPending()
- : base(DeflaterConstants.PendingBufSize)
- {
- }
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/GeneralBitFlags.cs b/src/ImageProcessor/Formats/Png/Zlib/GeneralBitFlags.cs
deleted file mode 100644
index d47bde407..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/GeneralBitFlags.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageProcessor.Formats
-{
- using System;
-
- ///
- /// Defines the contents of the general bit flags field for an archive entry.
- ///
- [Flags]
- public enum GeneralBitFlags
- {
- ///
- /// Bit 0 if set indicates that the file is encrypted
- ///
- Encrypted = 0x0001,
-
- ///
- /// Bits 1 and 2 - Two bits defining the compression method (only for Method 6 Imploding and 8,9 Deflating)
- ///
- Method = 0x0006,
-
- ///
- /// Bit 3 if set indicates a trailing data desciptor is appended to the entry data
- ///
- Descriptor = 0x0008,
-
- ///
- /// Bit 4 is reserved for use with method 8 for enhanced deflation
- ///
- ReservedPKware4 = 0x0010,
-
- ///
- /// Bit 5 if set indicates the file contains Pkzip compressed patched data.
- /// Requires version 2.7 or greater.
- ///
- Patched = 0x0020,
-
- ///
- /// Bit 6 if set indicates strong encryption has been used for this entry.
- ///
- StrongEncryption = 0x0040,
-
- ///
- /// Bit 7 is currently unused
- ///
- Unused7 = 0x0080,
-
- ///
- /// Bit 8 is currently unused
- ///
- Unused8 = 0x0100,
-
- ///
- /// Bit 9 is currently unused
- ///
- Unused9 = 0x0200,
-
- ///
- /// Bit 10 is currently unused
- ///
- Unused10 = 0x0400,
-
- ///
- /// Bit 11 if set indicates the filename and
- /// comment fields for this file must be encoded using UTF-8.
- ///
- UnicodeText = 0x0800,
-
- ///
- /// Bit 12 is documented as being reserved by PKware for enhanced compression.
- ///
- EnhancedCompress = 0x1000,
-
- ///
- /// Bit 13 if set indicates that values in the local header are masked to hide
- /// their actual values, and the central directory is encrypted.
- ///
- ///
- /// Used when encrypting the central directory contents.
- ///
- HeaderMasked = 0x2000,
-
- ///
- /// Bit 14 is documented as being reserved for use by PKware
- ///
- ReservedPkware14 = 0x4000,
-
- ///
- /// Bit 15 is documented as being reserved for use by PKware
- ///
- ReservedPkware15 = 0x8000
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/IChecksum.cs b/src/ImageProcessor/Formats/Png/Zlib/IChecksum.cs
index 7e6d65be1..d3ef70ed4 100644
--- a/src/ImageProcessor/Formats/Png/Zlib/IChecksum.cs
+++ b/src/ImageProcessor/Formats/Png/Zlib/IChecksum.cs
@@ -9,7 +9,7 @@ namespace ImageProcessor.Formats
/// Interface to compute a data checksum used by checked input/output streams.
/// A data checksum can be updated by one byte or with a byte array. After each
/// update the value of the current checksum can be returned by calling
- /// getValue. The complete checksum object can also be reset
+ /// Value. The complete checksum object can also be reset
/// so it can be used again with new data.
///
public interface IChecksum
diff --git a/src/ImageProcessor/Formats/Png/Zlib/Inflater.cs b/src/ImageProcessor/Formats/Png/Zlib/Inflater.cs
deleted file mode 100644
index 35a96741d..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/Inflater.cs
+++ /dev/null
@@ -1,843 +0,0 @@
-namespace ImageProcessor.Formats
-{
- using System;
-
- ///
- /// Inflater is used to decompress data that has been compressed according
- /// to the "deflate" standard described in rfc1951.
- ///
- /// By default Zlib (rfc1950) headers and footers are expected in the input.
- /// You can use constructor public Inflater(bool noHeader) passing true
- /// if there is no Zlib header information
- ///
- /// The usage is as following. First you have to set some input with
- /// SetInput(), then Inflate() it. If inflate doesn't
- /// inflate any bytes there may be three reasons:
- ///
- /// - IsNeedingInput() returns true because the input buffer is empty.
- /// You have to provide more input with
SetInput().
- /// NOTE: IsNeedingInput() also returns true when, the stream is finished.
- ///
- /// - IsNeedingDictionary() returns true, you have to provide a preset
- /// dictionary with
SetDictionary().
- /// - IsFinished returns true, the inflater has finished.
- ///
- /// Once the first output byte is produced, a dictionary will not be
- /// needed at a later stage.
- ///
- /// author of the original java version : John Leuner, Jochen Hoenicke
- ///
- public class Inflater
- {
- ///
- /// Copy lengths for literal codes 257..285
- ///
- private static readonly int[] CPLENS =
- {
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
- };
-
- ///
- /// Extra bits for literal codes 257..285
- ///
- private static readonly int[] CPLEXT =
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
- 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
- };
-
- ///
- /// Copy offsets for distance codes 0..29
- ///
- private static readonly int[] CPDIST =
- {
- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
- 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
- 8193, 12289, 16385, 24577
- };
-
- ///
- /// Extra bits for distance codes
- ///
- private static readonly int[] CPDEXT =
- {
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
- 12, 12, 13, 13
- };
-
- ///
- /// These are the possible states for an inflater
- ///
- private const int DECODE_HEADER = 0;
- private const int DECODE_DICT = 1;
- private const int DECODE_BLOCKS = 2;
- private const int DECODE_STORED_LEN1 = 3;
- private const int DECODE_STORED_LEN2 = 4;
- private const int DECODE_STORED = 5;
- private const int DECODE_DYN_HEADER = 6;
- private const int DECODE_HUFFMAN = 7;
- private const int DECODE_HUFFMAN_LENBITS = 8;
- private const int DECODE_HUFFMAN_DIST = 9;
- private const int DECODE_HUFFMAN_DISTBITS = 10;
- private const int DECODE_CHKSUM = 11;
- private const int FINISHED = 12;
-
- ///
- /// This variable contains the current state.
- ///
- private int mode;
-
- ///
- /// The adler checksum of the dictionary or of the decompressed
- /// stream, as it is written in the header resp. footer of the
- /// compressed stream.
- /// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
- ///
- private int readAdler;
-
- ///
- /// The number of bits needed to complete the current state. This
- /// is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
- /// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.
- ///
- private int neededBits;
- private int repLength;
- private int repDist;
- private int uncomprLen;
-
- ///
- /// True, if the last block flag was set in the last block of the
- /// inflated stream. This means that the stream ends after the
- /// current block.
- ///
- private bool isLastBlock;
-
- ///
- /// The total number of inflated bytes.
- ///
- private long totalOut;
-
- ///
- /// The total number of bytes set with setInput(). This is not the
- /// value returned by the TotalIn property, since this also includes the
- /// unprocessed input.
- ///
- private long totalIn;
-
- ///
- /// This variable stores the noHeader flag that was given to the constructor.
- /// True means, that the inflated stream doesn't contain a Zlib header or
- /// footer.
- ///
- private bool noHeader;
-
- private StreamManipulator input;
- private OutputWindow outputWindow;
- private InflaterDynHeader dynHeader;
- private InflaterHuffmanTree litlenTree, distTree;
- private Adler32 adler;
-
- ///
- /// Initializes a new instance of the class.
- /// RFC1950/Zlib headers and footers will be expected in the input data
- ///
- public Inflater()
- : this(false)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// True if no RFC1950/Zlib header and footer fields are expected in the input data
- ///
- /// This is used for GZIPed/Zipped input.
- ///
- /// For compatibility with
- /// Sun JDK you should provide one byte of input more than needed in
- /// this case.
- ///
- public Inflater(bool noHeader)
- {
- this.noHeader = noHeader;
- this.adler = new Adler32();
- this.input = new StreamManipulator();
- this.outputWindow = new OutputWindow();
- this.mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
- }
-
- ///
- /// Resets the inflater so that a new stream can be decompressed. All
- /// pending input and output will be discarded.
- ///
- public void Reset()
- {
- this.mode = this.noHeader ? DECODE_BLOCKS : DECODE_HEADER;
- this.totalIn = 0;
- this.totalOut = 0;
- this.input.Reset();
- this.outputWindow.Reset();
- this.dynHeader = null;
- this.litlenTree = null;
- this.distTree = null;
- this.isLastBlock = false;
- this.adler.Reset();
- }
-
- ///
- /// Decodes a zlib/RFC1950 header.
- ///
- ///
- /// False if more input is needed.
- ///
- ///
- /// The header is invalid.
- ///
- private bool DecodeHeader()
- {
- int header = this.input.PeekBits(16);
- if (header < 0)
- {
- return false;
- }
-
- this.input.DropBits(16);
-
- // The header is written in "wrong" byte order
- header = ((header << 8) | (header >> 8)) & 0xffff;
- if (header % 31 != 0)
- {
- throw new ImageFormatException("Header checksum illegal");
- }
-
- if ((header & 0x0f00) != (Deflater.Deflated << 8))
- {
- throw new ImageFormatException("Compression Method unknown");
- }
-
- /* Maximum size of the backwards window in bits.
- * We currently ignore this, but we could use it to make the
- * inflater window more space efficient. On the other hand the
- * full window (15 bits) is needed most times, anyway.
- int max_wbits = ((header & 0x7000) >> 12) + 8;
- */
-
- if ((header & 0x0020) == 0)
- { // Dictionary flag?
- this.mode = DECODE_BLOCKS;
- }
- else
- {
- this.mode = DECODE_DICT;
- this.neededBits = 32;
- }
-
- return true;
- }
-
- ///
- /// Decodes the dictionary checksum after the deflate header.
- ///
- ///
- /// False if more input is needed.
- ///
- private bool DecodeDict()
- {
- while (this.neededBits > 0)
- {
- int dictByte = this.input.PeekBits(8);
- if (dictByte < 0)
- {
- return false;
- }
-
- this.input.DropBits(8);
- this.readAdler = (this.readAdler << 8) | dictByte;
- this.neededBits -= 8;
- }
-
- return false;
- }
-
- ///
- /// Decodes the huffman encoded symbols in the input stream.
- ///
- ///
- /// false if more input is needed, true if output window is
- /// full or the current block ends.
- ///
- ///
- /// if deflated stream is invalid.
- ///
- private bool DecodeHuffman()
- {
- int free = this.outputWindow.GetFreeSpace();
- while (free >= 258)
- {
- int symbol;
- switch (this.mode)
- {
- case DECODE_HUFFMAN:
- // This is the inner loop so it is optimized a bit
- while (((symbol = this.litlenTree.GetSymbol(this.input)) & ~0xff) == 0)
- {
- this.outputWindow.Write(symbol);
- if (--free < 258)
- {
- return true;
- }
- }
-
- if (symbol < 257)
- {
- if (symbol < 0)
- {
- return false;
- }
- else
- {
- // symbol == 256: end of block
- this.distTree = null;
- this.litlenTree = null;
- this.mode = DECODE_BLOCKS;
- return true;
- }
- }
-
- try
- {
- this.repLength = CPLENS[symbol - 257];
- this.neededBits = CPLEXT[symbol - 257];
- }
- catch (Exception)
- {
- throw new ImageFormatException("Illegal rep length code");
- }
-
- goto case DECODE_HUFFMAN_LENBITS; // fall through
-
- case DECODE_HUFFMAN_LENBITS:
- if (this.neededBits > 0)
- {
- this.mode = DECODE_HUFFMAN_LENBITS;
- int i = this.input.PeekBits(this.neededBits);
- if (i < 0)
- {
- return false;
- }
-
- this.input.DropBits(this.neededBits);
- this.repLength += i;
- }
-
- this.mode = DECODE_HUFFMAN_DIST;
- goto case DECODE_HUFFMAN_DIST; // fall through
-
- case DECODE_HUFFMAN_DIST:
- symbol = this.distTree.GetSymbol(this.input);
- if (symbol < 0)
- {
- return false;
- }
-
- try
- {
- this.repDist = CPDIST[symbol];
- this.neededBits = CPDEXT[symbol];
- }
- catch (Exception)
- {
- throw new ImageFormatException("Illegal rep dist code");
- }
-
- goto case DECODE_HUFFMAN_DISTBITS; // fall through
-
- case DECODE_HUFFMAN_DISTBITS:
- if (this.neededBits > 0)
- {
- this.mode = DECODE_HUFFMAN_DISTBITS;
- int i = this.input.PeekBits(this.neededBits);
- if (i < 0)
- {
- return false;
- }
-
- this.input.DropBits(this.neededBits);
- this.repDist += i;
- }
-
- this.outputWindow.Repeat(this.repLength, this.repDist);
- free -= this.repLength;
- this.mode = DECODE_HUFFMAN;
- break;
-
- default:
- throw new ImageFormatException("Inflater unknown mode");
- }
- }
-
- return true;
- }
-
- ///
- /// Decodes the adler checksum after the deflate stream.
- ///
- ///
- /// false if more input is needed.
- ///
- ///
- /// If checksum doesn't match.
- ///
- private bool DecodeChksum()
- {
- while (this.neededBits > 0)
- {
- int chkByte = this.input.PeekBits(8);
- if (chkByte < 0)
- {
- return false;
- }
-
- this.input.DropBits(8);
- this.readAdler = (this.readAdler << 8) | chkByte;
- this.neededBits -= 8;
- }
-
- if ((int)this.adler.Value != this.readAdler)
- {
- throw new ImageFormatException("Adler chksum doesn't match: " + (int)this.adler.Value + " vs. " + this.readAdler);
- }
-
- this.mode = FINISHED;
- return false;
- }
-
- ///
- /// Decodes the deflated stream.
- ///
- ///
- /// false if more input is needed, or if finished.
- ///
- ///
- /// if deflated stream is invalid.
- ///
- private bool Decode()
- {
- switch (this.mode)
- {
- case DECODE_HEADER:
- return this.DecodeHeader();
-
- case DECODE_DICT:
- return this.DecodeDict();
-
- case DECODE_CHKSUM:
- return this.DecodeChksum();
-
- case DECODE_BLOCKS:
- if (this.isLastBlock)
- {
- if (this.noHeader)
- {
- this.mode = FINISHED;
- return false;
- }
- else
- {
- this.input.SkipToByteBoundary();
- this.neededBits = 32;
- this.mode = DECODE_CHKSUM;
- return true;
- }
- }
-
- int type = this.input.PeekBits(3);
- if (type < 0)
- {
- return false;
- }
-
- this.input.DropBits(3);
-
- if ((type & 1) != 0)
- {
- this.isLastBlock = true;
- }
-
- switch (type >> 1)
- {
- case DeflaterConstants.StoredBlock:
- this.input.SkipToByteBoundary();
- this.mode = DECODE_STORED_LEN1;
- break;
- case DeflaterConstants.StaticTrees:
- this.litlenTree = InflaterHuffmanTree.defLitLenTree;
- this.distTree = InflaterHuffmanTree.defDistTree;
- this.mode = DECODE_HUFFMAN;
- break;
- case DeflaterConstants.DynTrees:
- this.dynHeader = new InflaterDynHeader();
- this.mode = DECODE_DYN_HEADER;
- break;
- default:
- throw new ImageFormatException("Unknown block type " + type);
- }
-
- return true;
-
- case DECODE_STORED_LEN1:
- {
- if ((this.uncomprLen = this.input.PeekBits(16)) < 0)
- {
- return false;
- }
-
- this.input.DropBits(16);
- this.mode = DECODE_STORED_LEN2;
- }
-
- goto case DECODE_STORED_LEN2; // fall through
-
- case DECODE_STORED_LEN2:
- {
- int nlen = this.input.PeekBits(16);
- if (nlen < 0)
- {
- return false;
- }
-
- this.input.DropBits(16);
- if (nlen != (this.uncomprLen ^ 0xffff))
- {
- throw new ImageFormatException("broken uncompressed block");
- }
-
- this.mode = DECODE_STORED;
- }
-
- goto case DECODE_STORED; // fall through
-
- case DECODE_STORED:
- {
- int more = this.outputWindow.CopyStored(this.input, this.uncomprLen);
- this.uncomprLen -= more;
- if (this.uncomprLen == 0)
- {
- this.mode = DECODE_BLOCKS;
- return true;
- }
-
- return !this.input.IsNeedingInput;
- }
-
- case DECODE_DYN_HEADER:
- if (!this.dynHeader.Decode(this.input))
- {
- return false;
- }
-
- this.litlenTree = this.dynHeader.BuildLitLenTree();
- this.distTree = this.dynHeader.BuildDistTree();
- this.mode = DECODE_HUFFMAN;
- goto case DECODE_HUFFMAN; // fall through
-
- case DECODE_HUFFMAN:
- case DECODE_HUFFMAN_LENBITS:
- case DECODE_HUFFMAN_DIST:
- case DECODE_HUFFMAN_DISTBITS:
- return this.DecodeHuffman();
-
- case FINISHED:
- return false;
-
- default:
- throw new ImageFormatException("Inflater.Decode unknown mode");
- }
- }
-
- ///
- /// Sets the preset dictionary. This should only be called, if
- /// needsDictionary() returns true and it should set the same
- /// dictionary, that was used for deflating. The getAdler()
- /// function returns the checksum of the dictionary needed.
- ///
- ///
- /// The dictionary.
- ///
- public void SetDictionary(byte[] buffer)
- {
- this.SetDictionary(buffer, 0, buffer.Length);
- }
-
- ///
- /// Sets the preset dictionary. This should only be called, if
- /// needsDictionary() returns true and it should set the same
- /// dictionary, that was used for deflating. The getAdler()
- /// function returns the checksum of the dictionary needed.
- ///
- ///
- /// The dictionary.
- ///
- ///
- /// The index into buffer where the dictionary starts.
- ///
- ///
- /// The number of bytes in the dictionary.
- ///
- ///
- /// No dictionary is needed.
- ///
- ///
- /// The adler checksum for the buffer is invalid
- ///
- public void SetDictionary(byte[] buffer, int index, int count)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
-
- if (index < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
-
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(count));
- }
-
- if (!this.IsNeedingDictionary)
- {
- throw new InvalidOperationException("Dictionary is not needed");
- }
-
- this.adler.Update(buffer, index, count);
-
- if ((int)this.adler.Value != this.readAdler)
- {
- throw new ImageFormatException("Wrong adler checksum");
- }
-
- this.adler.Reset();
- this.outputWindow.CopyDict(buffer, index, count);
- this.mode = DECODE_BLOCKS;
- }
-
- ///
- /// Sets the input. This should only be called, if needsInput()
- /// returns true.
- ///
- ///
- /// the input.
- ///
- public void SetInput(byte[] buffer)
- {
- this.SetInput(buffer, 0, buffer.Length);
- }
-
- ///
- /// Sets the input. This should only be called, if needsInput()
- /// returns true.
- ///
- ///
- /// The source of input data
- ///
- ///
- /// The index into buffer where the input starts.
- ///
- ///
- /// The number of bytes of input to use.
- ///
- ///
- /// No input is needed.
- ///
- ///
- /// The index and/or count are wrong.
- ///
- public void SetInput(byte[] buffer, int index, int count)
- {
- this.input.SetInput(buffer, index, count);
- this.totalIn += (long)count;
- }
-
- ///
- /// Inflates the compressed stream to the output buffer. If this
- /// returns 0, you should check, whether IsNeedingDictionary(),
- /// IsNeedingInput() or IsFinished() returns true, to determine why no
- /// further output is produced.
- ///
- ///
- /// the output buffer.
- ///
- ///
- /// The number of bytes written to the buffer, 0 if no further
- /// output can be produced.
- ///
- ///
- /// if buffer has length 0.
- ///
- ///
- /// if deflated stream is invalid.
- ///
- public int Inflate(byte[] buffer)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
-
- return this.Inflate(buffer, 0, buffer.Length);
- }
-
- ///
- /// Inflates the compressed stream to the output buffer. If this
- /// returns 0, you should check, whether needsDictionary(),
- /// needsInput() or finished() returns true, to determine why no
- /// further output is produced.
- ///
- ///
- /// the output buffer.
- ///
- ///
- /// the offset in buffer where storing starts.
- ///
- ///
- /// the maximum number of bytes to output.
- ///
- ///
- /// the number of bytes written to the buffer, 0 if no further output can be produced.
- ///
- ///
- /// if count is less than 0.
- ///
- ///
- /// if the index and / or count are wrong.
- ///
- ///
- /// if deflated stream is invalid.
- ///
- public int Inflate(byte[] buffer, int offset, int count)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
-
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(count), "count cannot be negative");
- }
-
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(offset), "offset cannot be negative");
- }
-
- if (offset + count > buffer.Length)
- {
- throw new ArgumentException("count exceeds buffer bounds");
- }
-
- // Special case: count may be zero
- if (count == 0)
- {
- if (!this.IsFinished)
- { // -jr- 08-Nov-2003 INFLATE_BUG fix..
- this.Decode();
- }
-
- return 0;
- }
-
- int bytesCopied = 0;
-
- do
- {
- if (this.mode != DECODE_CHKSUM)
- {
- /* Don't give away any output, if we are waiting for the
- * checksum in the input stream.
- *
- * With this trick we have always:
- * IsNeedingInput() and not IsFinished()
- * implies more output can be produced.
- */
- int more = this.outputWindow.CopyOutput(buffer, offset, count);
- if (more > 0)
- {
- this.adler.Update(buffer, offset, more);
- offset += more;
- bytesCopied += more;
- this.totalOut += (long)more;
- count -= more;
- if (count == 0)
- {
- return bytesCopied;
- }
- }
- }
- }
- while (this.Decode() || ((this.outputWindow.GetAvailable() > 0) && (this.mode != DECODE_CHKSUM)));
- return bytesCopied;
- }
-
- ///
- /// Returns true, if the input buffer is empty.
- /// You should then call setInput().
- /// NOTE: This method also returns true when the stream is finished.
- ///
- public bool IsNeedingInput => this.input.IsNeedingInput;
-
- ///
- /// Returns true, if a preset dictionary is needed to inflate the input.
- ///
- public bool IsNeedingDictionary => this.mode == DECODE_DICT && this.neededBits == 0;
-
- ///
- /// Returns true, if the inflater has finished. This means, that no
- /// input is needed and no output can be produced.
- ///
- public bool IsFinished => this.mode == FINISHED && this.outputWindow.GetAvailable() == 0;
-
- ///
- /// Gets the adler checksum. This is either the checksum of all
- /// uncompressed bytes returned by inflate(), or if needsDictionary()
- /// returns true (and thus no output was yet produced) this is the
- /// adler checksum of the expected dictionary.
- ///
- ///
- /// the adler checksum.
- ///
- public int Adler => this.IsNeedingDictionary ? this.readAdler : (int)this.adler.Value;
-
- ///
- /// Gets the total number of output bytes returned by Inflate().
- ///
- ///
- /// the total number of output bytes.
- ///
- public long TotalOut => this.totalOut;
-
- ///
- /// Gets the total number of processed compressed input bytes.
- ///
- ///
- /// The total number of bytes of processed input bytes.
- ///
- public long TotalIn => this.totalIn - (long)this.RemainingInput;
-
- ///
- /// Gets the number of unprocessed input bytes. Useful, if the end of the
- /// stream is reached and you want to further process the bytes after
- /// the deflate stream.
- ///
- ///
- /// The number of bytes of the input which have not been processed.
- ///
- public int RemainingInput => this.input.AvailableBytes; // TODO: Should this be a long?
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/InflaterDynHeader.cs b/src/ImageProcessor/Formats/Png/Zlib/InflaterDynHeader.cs
deleted file mode 100644
index d1811dd3b..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/InflaterDynHeader.cs
+++ /dev/null
@@ -1,196 +0,0 @@
-namespace ImageProcessor.Formats
-{
- using System;
-
- class InflaterDynHeader
- {
- #region Constants
- const int LNUM = 0;
- const int DNUM = 1;
- const int BLNUM = 2;
- const int BLLENS = 3;
- const int LENS = 4;
- const int REPS = 5;
-
- static readonly int[] repMin = { 3, 3, 11 };
- static readonly int[] repBits = { 2, 3, 7 };
-
- static readonly int[] BL_ORDER =
- { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
-
- #endregion
-
- #region Constructors
- public InflaterDynHeader()
- {
- }
- #endregion
-
- public bool Decode(StreamManipulator input)
- {
- decode_loop:
- for (;;)
- {
- switch (mode)
- {
- case LNUM:
- lnum = input.PeekBits(5);
- if (lnum < 0)
- {
- return false;
- }
- lnum += 257;
- input.DropBits(5);
- // System.err.println("LNUM: "+lnum);
- mode = DNUM;
- goto case DNUM; // fall through
- case DNUM:
- dnum = input.PeekBits(5);
- if (dnum < 0)
- {
- return false;
- }
- dnum++;
- input.DropBits(5);
- // System.err.println("DNUM: "+dnum);
- num = lnum + dnum;
- litdistLens = new byte[num];
- mode = BLNUM;
- goto case BLNUM; // fall through
- case BLNUM:
- blnum = input.PeekBits(4);
- if (blnum < 0)
- {
- return false;
- }
- blnum += 4;
- input.DropBits(4);
- blLens = new byte[19];
- ptr = 0;
- // System.err.println("BLNUM: "+blnum);
- mode = BLLENS;
- goto case BLLENS; // fall through
- case BLLENS:
- while (ptr < blnum)
- {
- int len = input.PeekBits(3);
- if (len < 0)
- {
- return false;
- }
- input.DropBits(3);
- // System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);
- blLens[BL_ORDER[ptr]] = (byte)len;
- ptr++;
- }
- blTree = new InflaterHuffmanTree(blLens);
- blLens = null;
- ptr = 0;
- mode = LENS;
- goto case LENS; // fall through
- case LENS:
- {
- int symbol;
- while (((symbol = blTree.GetSymbol(input)) & ~15) == 0)
- {
- /* Normal case: symbol in [0..15] */
-
- // System.err.println("litdistLens["+ptr+"]: "+symbol);
- litdistLens[ptr++] = lastLen = (byte)symbol;
-
- if (ptr == num)
- {
- /* Finished */
- return true;
- }
- }
-
- /* need more input ? */
- if (symbol < 0)
- {
- return false;
- }
-
- /* otherwise repeat code */
- if (symbol >= 17)
- {
- /* repeat zero */
- // System.err.println("repeating zero");
- lastLen = 0;
- }
- else
- {
- if (ptr == 0)
- {
- throw new ImageFormatException();
- }
- }
- repSymbol = symbol - 16;
- }
- mode = REPS;
- goto case REPS; // fall through
- case REPS:
- {
- int bits = repBits[repSymbol];
- int count = input.PeekBits(bits);
- if (count < 0)
- {
- return false;
- }
- input.DropBits(bits);
- count += repMin[repSymbol];
- // System.err.println("litdistLens repeated: "+count);
-
- if (ptr + count > num)
- {
- throw new ImageFormatException();
- }
- while (count-- > 0)
- {
- litdistLens[ptr++] = lastLen;
- }
-
- if (ptr == num)
- {
- /* Finished */
- return true;
- }
- }
- mode = LENS;
- goto decode_loop;
- }
- }
- }
-
- public InflaterHuffmanTree BuildLitLenTree()
- {
- byte[] litlenLens = new byte[lnum];
- Array.Copy(litdistLens, 0, litlenLens, 0, lnum);
- return new InflaterHuffmanTree(litlenLens);
- }
-
- public InflaterHuffmanTree BuildDistTree()
- {
- byte[] distLens = new byte[dnum];
- Array.Copy(litdistLens, lnum, distLens, 0, dnum);
- return new InflaterHuffmanTree(distLens);
- }
-
- #region Instance Fields
- byte[] blLens;
- byte[] litdistLens;
-
- InflaterHuffmanTree blTree;
-
- ///
- /// The current decode mode
- ///
- int mode;
- int lnum, dnum, blnum, num;
- int repSymbol;
- byte lastLen;
- int ptr;
- #endregion
-
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/InflaterHuffmanTree.cs b/src/ImageProcessor/Formats/Png/Zlib/InflaterHuffmanTree.cs
deleted file mode 100644
index f6b7332f5..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/InflaterHuffmanTree.cs
+++ /dev/null
@@ -1,225 +0,0 @@
-namespace ImageProcessor.Formats
-{
- using System;
-
- ///
- /// Huffman tree used for inflation
- ///
- public class InflaterHuffmanTree
- {
- #region Constants
- const int MAX_BITLEN = 15;
- #endregion
-
- #region Instance Fields
- short[] tree;
- #endregion
-
- ///
- /// Literal length tree
- ///
- public static InflaterHuffmanTree defLitLenTree;
-
- ///
- /// Distance tree
- ///
- public static InflaterHuffmanTree defDistTree;
-
- static InflaterHuffmanTree()
- {
- try
- {
- byte[] codeLengths = new byte[288];
- int i = 0;
- while (i < 144)
- {
- codeLengths[i++] = 8;
- }
- while (i < 256)
- {
- codeLengths[i++] = 9;
- }
- while (i < 280)
- {
- codeLengths[i++] = 7;
- }
- while (i < 288)
- {
- codeLengths[i++] = 8;
- }
- defLitLenTree = new InflaterHuffmanTree(codeLengths);
-
- codeLengths = new byte[32];
- i = 0;
- while (i < 32)
- {
- codeLengths[i++] = 5;
- }
- defDistTree = new InflaterHuffmanTree(codeLengths);
- }
- catch (Exception)
- {
- throw new ImageFormatException("InflaterHuffmanTree: static tree length illegal");
- }
- }
-
- #region Constructors
- ///
- /// Constructs a Huffman tree from the array of code lengths.
- ///
- ///
- /// the array of code lengths
- ///
- public InflaterHuffmanTree(byte[] codeLengths)
- {
- BuildTree(codeLengths);
- }
- #endregion
-
- void BuildTree(byte[] codeLengths)
- {
- int[] blCount = new int[MAX_BITLEN + 1];
- int[] nextCode = new int[MAX_BITLEN + 1];
-
- for (int i = 0; i < codeLengths.Length; i++)
- {
- int bits = codeLengths[i];
- if (bits > 0)
- {
- blCount[bits]++;
- }
- }
-
- int code = 0;
- int treeSize = 512;
- for (int bits = 1; bits <= MAX_BITLEN; bits++)
- {
- nextCode[bits] = code;
- code += blCount[bits] << (16 - bits);
- if (bits >= 10)
- {
- /* We need an extra table for bit lengths >= 10. */
- int start = nextCode[bits] & 0x1ff80;
- int end = code & 0x1ff80;
- treeSize += (end - start) >> (16 - bits);
- }
- }
-
- /* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g
- if (code != 65536)
- {
- throw new SharpZipBaseException("Code lengths don't add up properly.");
- }
- */
- /* Now create and fill the extra tables from longest to shortest
- * bit len. This way the sub trees will be aligned.
- */
- tree = new short[treeSize];
- int treePtr = 512;
- for (int bits = MAX_BITLEN; bits >= 10; bits--)
- {
- int end = code & 0x1ff80;
- code -= blCount[bits] << (16 - bits);
- int start = code & 0x1ff80;
- for (int i = start; i < end; i += 1 << 7)
- {
- tree[DeflaterHuffman.BitReverse(i)] = (short)((-treePtr << 4) | bits);
- treePtr += 1 << (bits - 9);
- }
- }
-
- for (int i = 0; i < codeLengths.Length; i++)
- {
- int bits = codeLengths[i];
- if (bits == 0)
- {
- continue;
- }
- code = nextCode[bits];
- int revcode = DeflaterHuffman.BitReverse(code);
- if (bits <= 9)
- {
- do
- {
- tree[revcode] = (short)((i << 4) | bits);
- revcode += 1 << bits;
- } while (revcode < 512);
- }
- else
- {
- int subTree = tree[revcode & 511];
- int treeLen = 1 << (subTree & 15);
- subTree = -(subTree >> 4);
- do
- {
- tree[subTree | (revcode >> 9)] = (short)((i << 4) | bits);
- revcode += 1 << bits;
- } while (revcode < treeLen);
- }
- nextCode[bits] = code + (1 << (16 - bits));
- }
-
- }
-
- ///
- /// Reads the next symbol from input. The symbol is encoded using the
- /// huffman tree.
- ///
- ///
- /// input the input source.
- ///
- ///
- /// the next symbol, or -1 if not enough input is available.
- ///
- public int GetSymbol(StreamManipulator input)
- {
- int lookahead, symbol;
- if ((lookahead = input.PeekBits(9)) >= 0)
- {
- if ((symbol = tree[lookahead]) >= 0)
- {
- input.DropBits(symbol & 15);
- return symbol >> 4;
- }
- int subtree = -(symbol >> 4);
- int bitlen = symbol & 15;
- if ((lookahead = input.PeekBits(bitlen)) >= 0)
- {
- symbol = tree[subtree | (lookahead >> 9)];
- input.DropBits(symbol & 15);
- return symbol >> 4;
- }
- else
- {
- int bits = input.AvailableBits;
- lookahead = input.PeekBits(bits);
- symbol = tree[subtree | (lookahead >> 9)];
- if ((symbol & 15) <= bits)
- {
- input.DropBits(symbol & 15);
- return symbol >> 4;
- }
- else
- {
- return -1;
- }
- }
- }
- else
- {
- int bits = input.AvailableBits;
- lookahead = input.PeekBits(bits);
- symbol = tree[lookahead];
- if (symbol >= 0 && (symbol & 15) <= bits)
- {
- input.DropBits(symbol & 15);
- return symbol >> 4;
- }
- else
- {
- return -1;
- }
- }
- }
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/InflaterInputBuffer.cs b/src/ImageProcessor/Formats/Png/Zlib/InflaterInputBuffer.cs
deleted file mode 100644
index 5c70ad41c..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/InflaterInputBuffer.cs
+++ /dev/null
@@ -1,268 +0,0 @@
-namespace ImageProcessor.Formats
-{
- using System;
- using System.IO;
-
- ///
- /// An input buffer customised for use by
- ///
- ///
- /// The buffer supports decryption of incoming data.
- ///
- public class InflaterInputBuffer
- {
- ///
- /// Initialise a new instance of with a default buffer size
- ///
- /// The stream to buffer.
- public InflaterInputBuffer(Stream stream) : this(stream, 4096)
- {
- }
-
- ///
- /// Initialise a new instance of
- ///
- /// The stream to buffer.
- /// The size to use for the buffer
- /// A minimum buffer size of 1KB is permitted. Lower sizes are treated as 1KB.
- public InflaterInputBuffer(Stream stream, int bufferSize)
- {
- inputStream = stream;
- if (bufferSize < 1024)
- {
- bufferSize = 1024;
- }
- rawData = new byte[bufferSize];
- clearText = rawData;
- }
-
- ///
- /// Get the length of bytes bytes in the
- ///
- public int RawLength
- {
- get
- {
- return rawLength;
- }
- }
-
- ///
- /// Get the contents of the raw data buffer.
- ///
- /// This may contain encrypted data.
- public byte[] RawData
- {
- get
- {
- return rawData;
- }
- }
-
- ///
- /// Get the number of useable bytes in
- ///
- public int ClearTextLength
- {
- get
- {
- return clearTextLength;
- }
- }
-
- ///
- /// Get the contents of the clear text buffer.
- ///
- public byte[] ClearText
- {
- get
- {
- return clearText;
- }
- }
-
- ///
- /// Get/set the number of bytes available
- ///
- public int Available
- {
- get { return available; }
- set { available = value; }
- }
-
- ///
- /// Call passing the current clear text buffer contents.
- ///
- /// The inflater to set input for.
- public void SetInflaterInput(Inflater inflater)
- {
- if (available > 0)
- {
- inflater.SetInput(clearText, clearTextLength - available, available);
- available = 0;
- }
- }
-
- ///
- /// Fill the buffer from the underlying input stream.
- ///
- public void Fill()
- {
- rawLength = 0;
- int toRead = rawData.Length;
-
- while (toRead > 0)
- {
- int count = inputStream.Read(rawData, rawLength, toRead);
- if (count <= 0)
- {
- break;
- }
- rawLength += count;
- toRead -= count;
- }
-
- clearTextLength = rawLength;
- available = clearTextLength;
- }
-
- ///
- /// Read a buffer directly from the input stream
- ///
- /// The buffer to fill
- /// Returns the number of bytes read.
- public int ReadRawBuffer(byte[] buffer)
- {
- return ReadRawBuffer(buffer, 0, buffer.Length);
- }
-
- ///
- /// Read a buffer directly from the input stream
- ///
- /// The buffer to read into
- /// The offset to start reading data into.
- /// The number of bytes to read.
- /// Returns the number of bytes read.
- public int ReadRawBuffer(byte[] outBuffer, int offset, int length)
- {
- if (length < 0)
- {
- throw new ArgumentOutOfRangeException("length");
- }
-
- int currentOffset = offset;
- int currentLength = length;
-
- while (currentLength > 0)
- {
- if (available <= 0)
- {
- Fill();
- if (available <= 0)
- {
- return 0;
- }
- }
-
- int toCopy = Math.Min(currentLength, available);
- Array.Copy(rawData, rawLength - (int)available, outBuffer, currentOffset, toCopy);
- currentOffset += toCopy;
- currentLength -= toCopy;
- available -= toCopy;
- }
-
- return length;
- }
-
- ///
- /// Read clear text data from the input stream.
- ///
- /// The buffer to add data to.
- /// The offset to start adding data at.
- /// The number of bytes to read.
- /// Returns the number of bytes actually read.
- public int ReadClearTextBuffer(byte[] outBuffer, int offset, int length)
- {
- if (length < 0)
- {
- throw new ArgumentOutOfRangeException("length");
- }
-
- int currentOffset = offset;
- int currentLength = length;
-
- while (currentLength > 0)
- {
- if (available <= 0)
- {
- Fill();
- if (available <= 0)
- {
- return 0;
- }
- }
-
- int toCopy = Math.Min(currentLength, available);
- Array.Copy(clearText, clearTextLength - (int)available, outBuffer, currentOffset, toCopy);
- currentOffset += toCopy;
- currentLength -= toCopy;
- available -= toCopy;
- }
- return length;
- }
-
- ///
- /// Read a from the input stream.
- ///
- /// Returns the byte read.
- public int ReadLeByte()
- {
- if (available <= 0)
- {
- Fill();
- if (available <= 0)
- {
- throw new ImageFormatException("EOF in header");
- }
- }
- byte result = rawData[rawLength - available];
- available -= 1;
- return result;
- }
-
- ///
- /// Read an in little endian byte order.
- ///
- /// The short value read case to an int.
- public int ReadLeShort()
- {
- return ReadLeByte() | (ReadLeByte() << 8);
- }
-
- ///
- /// Read an in little endian byte order.
- ///
- /// The int value read.
- public int ReadLeInt()
- {
- return ReadLeShort() | (ReadLeShort() << 16);
- }
-
- ///
- /// Read a in little endian byte order.
- ///
- /// The long value read.
- public long ReadLeLong()
- {
- return (uint)ReadLeInt() | ((long)ReadLeInt() << 32);
- }
-
- int rawLength;
- byte[] rawData;
-
- int clearTextLength;
- byte[] clearText;
- int available;
- Stream inputStream;
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/InflaterInputStream.cs b/src/ImageProcessor/Formats/Png/Zlib/InflaterInputStream.cs
deleted file mode 100644
index b6a35e420..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/InflaterInputStream.cs
+++ /dev/null
@@ -1,397 +0,0 @@
-namespace ImageProcessor.Formats
-{
- using System;
- using System.IO;
-
- //using ICSharpCode.SharpZipLib;
- //using ICSharpCode.SharpZipLib.Zip;
- //using ICSharpCode.SharpZipLib.Zip.Compression;
-
- ///
- /// This filter stream is used to decompress data compressed using the "deflate"
- /// format. The "deflate" format is described in RFC 1951.
- ///
- /// This stream may form the basis for other decompression filters, such
- /// as the GZipInputStream.
- ///
- /// Author of the original java version : John Leuner.
- ///
- public class InflaterInputStream : Stream
- {
- #region Constructors
- ///
- /// Create an InflaterInputStream with the default decompressor
- /// and a default buffer size of 4KB.
- ///
- ///
- /// The InputStream to read bytes from
- ///
- public InflaterInputStream(Stream baseInputStream)
- : this(baseInputStream, new Inflater(), 4096)
- {
- }
-
- ///
- /// Create an InflaterInputStream with the specified decompressor
- /// and a default buffer size of 4KB.
- ///
- ///
- /// The source of input data
- ///
- ///
- /// The decompressor used to decompress data read from baseInputStream
- ///
- public InflaterInputStream(Stream baseInputStream, Inflater inf)
- : this(baseInputStream, inf, 4096)
- {
- }
-
- ///
- /// Create an InflaterInputStream with the specified decompressor and the specified buffer size.
- ///
- ///
- /// The InputStream to read bytes from
- ///
- ///
- /// The decompressor to use
- ///
- ///
- /// Size of the buffer to use
- ///
- public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize)
- {
- if (baseInputStream == null)
- {
- throw new ArgumentNullException("baseInputStream");
- }
-
- if (inflater == null)
- {
- throw new ArgumentNullException("inflater");
- }
-
- if (bufferSize <= 0)
- {
- throw new ArgumentOutOfRangeException("bufferSize");
- }
-
- this.baseInputStream = baseInputStream;
- this.inf = inflater;
-
- inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize);
- }
-
- #endregion
-
- ///
- /// Get/set flag indicating ownership of underlying stream.
- /// When the flag is true will close the underlying stream also.
- ///
- ///
- /// The default value is true.
- ///
- public bool IsStreamOwner
- {
- get { return isStreamOwner; }
- set { isStreamOwner = value; }
- }
-
- ///
- /// Skip specified number of bytes of uncompressed data
- ///
- ///
- /// Number of bytes to skip
- ///
- ///
- /// The number of bytes skipped, zero if the end of
- /// stream has been reached
- ///
- ///
- /// The number of bytes to skip is less than or equal to zero.
- ///
- public long Skip(long count)
- {
- if (count <= 0)
- {
- throw new ArgumentOutOfRangeException("count");
- }
-
- // v0.80 Skip by seeking if underlying stream supports it...
- if (baseInputStream.CanSeek)
- {
- baseInputStream.Seek(count, SeekOrigin.Current);
- return count;
- }
- else
- {
- int length = 2048;
- if (count < length)
- {
- length = (int)count;
- }
-
- byte[] tmp = new byte[length];
- int readCount = 1;
- long toSkip = count;
-
- while ((toSkip > 0) && (readCount > 0))
- {
- if (toSkip < length)
- {
- length = (int)toSkip;
- }
-
- readCount = baseInputStream.Read(tmp, 0, length);
- toSkip -= readCount;
- }
-
- return count - toSkip;
- }
- }
-
- ///
- /// Returns 0 once the end of the stream (EOF) has been reached.
- /// Otherwise returns 1.
- ///
- public virtual int Available
- {
- get
- {
- return inf.IsFinished ? 0 : 1;
- }
- }
-
- ///
- /// Fills the buffer with more data to decompress.
- ///
- ///
- /// Stream ends early
- ///
- protected void Fill()
- {
- // Protect against redundant calls
- if (inputBuffer.Available <= 0)
- {
- inputBuffer.Fill();
- if (inputBuffer.Available <= 0)
- {
- throw new ImageFormatException("Unexpected EOF");
- }
- }
- inputBuffer.SetInflaterInput(inf);
- }
-
- #region Stream Overrides
- ///
- /// Gets a value indicating whether the current stream supports reading
- ///
- public override bool CanRead
- {
- get
- {
- return baseInputStream.CanRead;
- }
- }
-
- ///
- /// Gets a value of false indicating seeking is not supported for this stream.
- ///
- public override bool CanSeek
- {
- get
- {
- return false;
- }
- }
-
- ///
- /// Gets a value of false indicating that this stream is not writeable.
- ///
- public override bool CanWrite
- {
- get
- {
- return false;
- }
- }
-
- ///
- /// A value representing the length of the stream in bytes.
- ///
- public override long Length
- {
- get
- {
- return inputBuffer.RawLength;
- }
- }
-
- ///
- /// The current position within the stream.
- /// Throws a NotSupportedException when attempting to set the position
- ///
- /// Attempting to set the position
- public override long Position
- {
- get
- {
- return baseInputStream.Position;
- }
- set
- {
- throw new NotSupportedException("InflaterInputStream Position not supported");
- }
- }
-
- ///
- /// Flushes the baseInputStream
- ///
- public override void Flush()
- {
- baseInputStream.Flush();
- }
-
- ///
- /// Sets the position within the current stream
- /// Always throws a NotSupportedException
- ///
- /// The relative offset to seek to.
- /// The defining where to seek from.
- /// The new position in the stream.
- /// Any access
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotSupportedException("Seek not supported");
- }
-
- ///
- /// Set the length of the current stream
- /// Always throws a NotSupportedException
- ///
- /// The new length value for the stream.
- /// Any access
- public override void SetLength(long value)
- {
- throw new NotSupportedException("InflaterInputStream SetLength not supported");
- }
-
- ///
- /// Writes a sequence of bytes to stream and advances the current position
- /// This method always throws a NotSupportedException
- ///
- /// Thew buffer containing data to write.
- /// The offset of the first byte to write.
- /// The number of bytes to write.
- /// Any access
- public override void Write(byte[] buffer, int offset, int count)
- {
- throw new NotSupportedException("InflaterInputStream Write not supported");
- }
-
- ///
- /// Writes one byte to the current stream and advances the current position
- /// Always throws a NotSupportedException
- ///
- /// The byte to write.
- /// Any access
- public override void WriteByte(byte value)
- {
- throw new NotSupportedException("InflaterInputStream WriteByte not supported");
- }
-
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
- if (disposing && !isClosed)
- {
- isClosed = true;
- if (isStreamOwner)
- {
- baseInputStream.Dispose();
- }
- }
- }
-
- ///
- /// Reads decompressed data into the provided buffer byte array
- ///
- ///
- /// The array to read and decompress data into
- ///
- ///
- /// The offset indicating where the data should be placed
- ///
- ///
- /// The number of bytes to decompress
- ///
- /// The number of bytes read. Zero signals the end of stream
- ///
- /// Inflater needs a dictionary
- ///
- public override int Read(byte[] buffer, int offset, int count)
- {
- if (inf.IsNeedingDictionary)
- {
- throw new ImageFormatException("Need a dictionary");
- }
-
- int remainingBytes = count;
- while (true)
- {
- int bytesRead = inf.Inflate(buffer, offset, remainingBytes);
- offset += bytesRead;
- remainingBytes -= bytesRead;
-
- if (remainingBytes == 0 || inf.IsFinished)
- {
- break;
- }
-
- if (inf.IsNeedingInput)
- {
- Fill();
- }
- else if (bytesRead == 0)
- {
- throw new ImageFormatException("Dont know what to do");
- }
- }
- return count - remainingBytes;
- }
- #endregion
-
- #region Instance Fields
- ///
- /// Decompressor for this stream
- ///
- protected Inflater inf;
-
- ///
- /// Input buffer for this stream.
- ///
- protected InflaterInputBuffer inputBuffer;
-
- ///
- /// Base stream the inflater reads from.
- ///
- private Stream baseInputStream;
-
- ///
- /// The compressed size
- ///
- protected long csize;
-
- ///
- /// Flag indicating wether this instance has been closed or not.
- ///
- bool isClosed;
-
- ///
- /// Flag indicating wether this instance is designated the stream owner.
- /// When closing if this flag is true the underlying stream is closed.
- ///
- bool isStreamOwner = true;
- #endregion
- }
-}
-
diff --git a/src/ImageProcessor/Formats/Png/Zlib/OutputWindow.cs b/src/ImageProcessor/Formats/Png/Zlib/OutputWindow.cs
deleted file mode 100644
index 353bebadd..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/OutputWindow.cs
+++ /dev/null
@@ -1,217 +0,0 @@
-namespace ImageProcessor.Formats
-{
- using System;
-
- ///
- /// Contains the output from the Inflation process.
- /// We need to have a window so that we can refer backwards into the output stream
- /// to repeat stuff.
- /// Author of the original java version : John Leuner
- ///
- public class OutputWindow
- {
- #region Constants
- const int WindowSize = 1 << 15;
- const int WindowMask = WindowSize - 1;
- #endregion
-
- #region Instance Fields
- byte[] window = new byte[WindowSize]; //The window is 2^15 bytes
- int windowEnd;
- int windowFilled;
- #endregion
-
- ///
- /// Write a byte to this output window
- ///
- /// value to write
- ///
- /// if window is full
- ///
- public void Write(int value)
- {
- if (windowFilled++ == WindowSize)
- {
- throw new InvalidOperationException("Window full");
- }
- window[windowEnd++] = (byte)value;
- windowEnd &= WindowMask;
- }
-
-
- private void SlowRepeat(int repStart, int length, int distance)
- {
- while (length-- > 0)
- {
- window[windowEnd++] = window[repStart++];
- windowEnd &= WindowMask;
- repStart &= WindowMask;
- }
- }
-
- ///
- /// Append a byte pattern already in the window itself
- ///
- /// length of pattern to copy
- /// distance from end of window pattern occurs
- ///
- /// If the repeated data overflows the window
- ///
- public void Repeat(int length, int distance)
- {
- if ((windowFilled += length) > WindowSize)
- {
- throw new InvalidOperationException("Window full");
- }
-
- int repStart = (windowEnd - distance) & WindowMask;
- int border = WindowSize - length;
- if ((repStart <= border) && (windowEnd < border))
- {
- if (length <= distance)
- {
- System.Array.Copy(window, repStart, window, windowEnd, length);
- windowEnd += length;
- }
- else
- {
- // We have to copy manually, since the repeat pattern overlaps.
- while (length-- > 0)
- {
- window[windowEnd++] = window[repStart++];
- }
- }
- }
- else
- {
- SlowRepeat(repStart, length, distance);
- }
- }
-
- ///
- /// Copy from input manipulator to internal window
- ///
- /// source of data
- /// length of data to copy
- /// the number of bytes copied
- public int CopyStored(StreamManipulator input, int length)
- {
- length = Math.Min(Math.Min(length, WindowSize - windowFilled), input.AvailableBytes);
- int copied;
-
- int tailLen = WindowSize - windowEnd;
- if (length > tailLen)
- {
- copied = input.CopyBytes(window, windowEnd, tailLen);
- if (copied == tailLen)
- {
- copied += input.CopyBytes(window, 0, length - tailLen);
- }
- }
- else
- {
- copied = input.CopyBytes(window, windowEnd, length);
- }
-
- windowEnd = (windowEnd + copied) & WindowMask;
- windowFilled += copied;
- return copied;
- }
-
- ///
- /// Copy dictionary to window
- ///
- /// source dictionary
- /// offset of start in source dictionary
- /// length of dictionary
- ///
- /// If window isnt empty
- ///
- public void CopyDict(byte[] dictionary, int offset, int length)
- {
- if (dictionary == null)
- {
- throw new ArgumentNullException("dictionary");
- }
-
- if (windowFilled > 0)
- {
- throw new InvalidOperationException();
- }
-
- if (length > WindowSize)
- {
- offset += length - WindowSize;
- length = WindowSize;
- }
- System.Array.Copy(dictionary, offset, window, 0, length);
- windowEnd = length & WindowMask;
- }
-
- ///
- /// Get remaining unfilled space in window
- ///
- /// Number of bytes left in window
- public int GetFreeSpace()
- {
- return WindowSize - windowFilled;
- }
-
- ///
- /// Get bytes available for output in window
- ///
- /// Number of bytes filled
- public int GetAvailable()
- {
- return windowFilled;
- }
-
- ///
- /// Copy contents of window to output
- ///
- /// buffer to copy to
- /// offset to start at
- /// number of bytes to count
- /// The number of bytes copied
- ///
- /// If a window underflow occurs
- ///
- public int CopyOutput(byte[] output, int offset, int len)
- {
- int copyEnd = windowEnd;
- if (len > windowFilled)
- {
- len = windowFilled;
- }
- else
- {
- copyEnd = (windowEnd - windowFilled + len) & WindowMask;
- }
-
- int copied = len;
- int tailLen = len - copyEnd;
-
- if (tailLen > 0)
- {
- System.Array.Copy(window, WindowSize - tailLen, output, offset, tailLen);
- offset += tailLen;
- len = copyEnd;
- }
- System.Array.Copy(window, copyEnd - len, output, offset, len);
- windowFilled -= copied;
- if (windowFilled < 0)
- {
- throw new InvalidOperationException();
- }
- return copied;
- }
-
- ///
- /// Reset by clearing window so GetAvailable returns 0
- ///
- public void Reset()
- {
- windowFilled = windowEnd = 0;
- }
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/PendingBuffer.cs b/src/ImageProcessor/Formats/Png/Zlib/PendingBuffer.cs
deleted file mode 100644
index 001558f4a..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/PendingBuffer.cs
+++ /dev/null
@@ -1,217 +0,0 @@
-namespace ImageProcessor.Formats
-{
- ///
- /// This class is general purpose class for writing data to a buffer.
- ///
- /// It allows you to write bits as well as bytes
- /// Based on DeflaterPending.java
- ///
- /// author of the original java version : Jochen Hoenicke
- ///
- public class PendingBuffer
- {
- #region Instance Fields
- ///
- /// Internal work buffer
- ///
- byte[] buffer_;
-
- int start;
- int end;
-
- uint bits;
- int bitCount;
- #endregion
-
- #region Constructors
- ///
- /// construct instance using default buffer size of 4096
- ///
- public PendingBuffer() : this(4096)
- {
- }
-
- ///
- /// construct instance using specified buffer size
- ///
- ///
- /// size to use for internal buffer
- ///
- public PendingBuffer(int bufferSize)
- {
- buffer_ = new byte[bufferSize];
- }
-
- #endregion
-
- ///
- /// Clear internal state/buffers
- ///
- public void Reset()
- {
- start = end = bitCount = 0;
- }
-
- ///
- /// Write a byte to buffer
- ///
- ///
- /// The value to write
- ///
- public void WriteByte(int value)
- {
- buffer_[end++] = unchecked((byte)value);
- }
-
- ///
- /// Write a short value to buffer LSB first
- ///
- ///
- /// The value to write.
- ///
- public void WriteShort(int value)
- {
- buffer_[end++] = unchecked((byte)value);
- buffer_[end++] = unchecked((byte)(value >> 8));
- }
-
- ///
- /// write an integer LSB first
- ///
- /// The value to write.
- public void WriteInt(int value)
- {
- buffer_[end++] = unchecked((byte)value);
- buffer_[end++] = unchecked((byte)(value >> 8));
- buffer_[end++] = unchecked((byte)(value >> 16));
- buffer_[end++] = unchecked((byte)(value >> 24));
- }
-
- ///
- /// Write a block of data to buffer
- ///
- /// data to write
- /// offset of first byte to write
- /// number of bytes to write
- public void WriteBlock(byte[] block, int offset, int length)
- {
- System.Array.Copy(block, offset, buffer_, end, length);
- end += length;
- }
-
- ///
- /// The number of bits written to the buffer
- ///
- public int BitCount
- {
- get
- {
- return bitCount;
- }
- }
-
- ///
- /// Align internal buffer on a byte boundary
- ///
- public void AlignToByte()
- {
- if (bitCount > 0)
- {
- buffer_[end++] = unchecked((byte)bits);
- if (bitCount > 8)
- {
- buffer_[end++] = unchecked((byte)(bits >> 8));
- }
- }
- bits = 0;
- bitCount = 0;
- }
-
- ///
- /// Write bits to internal buffer
- ///
- /// source of bits
- /// number of bits to write
- public void WriteBits(int b, int count)
- {
- bits |= (uint)(b << bitCount);
- bitCount += count;
- if (bitCount >= 16)
- {
- buffer_[end++] = unchecked((byte)bits);
- buffer_[end++] = unchecked((byte)(bits >> 8));
- bits >>= 16;
- bitCount -= 16;
- }
- }
-
- ///
- /// Write a short value to internal buffer most significant byte first
- ///
- /// value to write
- public void WriteShortMSB(int s)
- {
- buffer_[end++] = unchecked((byte)(s >> 8));
- buffer_[end++] = unchecked((byte)s);
- }
-
- ///
- /// Indicates if buffer has been flushed
- ///
- public bool IsFlushed
- {
- get
- {
- return end == 0;
- }
- }
-
- ///
- /// Flushes the pending buffer into the given output array. If the
- /// output array is to small, only a partial flush is done.
- ///
- /// The output array.
- /// The offset into output array.
- /// The maximum number of bytes to store.
- /// The number of bytes flushed.
- public int Flush(byte[] output, int offset, int length)
- {
- if (bitCount >= 8)
- {
- buffer_[end++] = unchecked((byte)bits);
- bits >>= 8;
- bitCount -= 8;
- }
-
- if (length > end - start)
- {
- length = end - start;
- System.Array.Copy(buffer_, start, output, offset, length);
- start = 0;
- end = 0;
- }
- else
- {
- System.Array.Copy(buffer_, start, output, offset, length);
- start += length;
- }
- return length;
- }
-
- ///
- /// Convert internal buffer to byte array.
- /// Buffer is empty on completion
- ///
- ///
- /// The internal buffer contents converted to a byte array.
- ///
- public byte[] ToByteArray()
- {
- byte[] result = new byte[end - start];
- System.Array.Copy(buffer_, start, result, 0, result.Length);
- start = 0;
- end = 0;
- return result;
- }
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/README.md b/src/ImageProcessor/Formats/Png/Zlib/README.md
index eca351910..c297a91d5 100644
--- a/src/ImageProcessor/Formats/Png/Zlib/README.md
+++ b/src/ImageProcessor/Formats/Png/Zlib/README.md
@@ -1,2 +1,2 @@
-The contents of this folder have been copied from https://github.com/ygrenier/SharpZipLib.Portable
-in order to allow the project to run the NET 4.6 portable classes.
+Adler32.cs and Crc32.cs have been copied from
+https://github.com/ygrenier/SharpZipLib.Portable
diff --git a/src/ImageProcessor/Formats/Png/Zlib/StreamManipulator.cs b/src/ImageProcessor/Formats/Png/Zlib/StreamManipulator.cs
deleted file mode 100644
index 1f934558d..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/StreamManipulator.cs
+++ /dev/null
@@ -1,279 +0,0 @@
-namespace ImageProcessor.Formats
-{
- using System;
-
- ///
- /// This class allows us to retrieve a specified number of bits from
- /// the input buffer, as well as copy big byte blocks.
- ///
- /// It uses an int buffer to store up to 31 bits for direct
- /// manipulation. This guarantees that we can get at least 16 bits,
- /// but we only need at most 15, so this is all safe.
- ///
- /// There are some optimizations in this class, for example, you must
- /// never peek more than 8 bits more than needed, and you must first
- /// peek bits before you may drop them. This is not a general purpose
- /// class but optimized for the behaviour of the Inflater.
- ///
- /// authors of the original java version : John Leuner, Jochen Hoenicke
- ///
- public class StreamManipulator
- {
- #region Constructors
- ///
- /// Constructs a default StreamManipulator with all buffers empty
- ///
- public StreamManipulator()
- {
- }
- #endregion
-
- ///
- /// Get the next sequence of bits but don't increase input pointer. bitCount must be
- /// less or equal 16 and if this call succeeds, you must drop
- /// at least n - 8 bits in the next call.
- ///
- /// The number of bits to peek.
- ///
- /// the value of the bits, or -1 if not enough bits available. */
- ///
- public int PeekBits(int bitCount)
- {
- if (bitsInBuffer_ < bitCount)
- {
- if (windowStart_ == windowEnd_)
- {
- return -1; // ok
- }
- buffer_ |= (uint)((window_[windowStart_++] & 0xff |
- (window_[windowStart_++] & 0xff) << 8) << bitsInBuffer_);
- bitsInBuffer_ += 16;
- }
- return (int)(buffer_ & ((1 << bitCount) - 1));
- }
-
- ///
- /// Drops the next n bits from the input. You should have called PeekBits
- /// with a bigger or equal n before, to make sure that enough bits are in
- /// the bit buffer.
- ///
- /// The number of bits to drop.
- public void DropBits(int bitCount)
- {
- buffer_ >>= bitCount;
- bitsInBuffer_ -= bitCount;
- }
-
- ///
- /// Gets the next n bits and increases input pointer. This is equivalent
- /// to followed by , except for correct error handling.
- ///
- /// The number of bits to retrieve.
- ///
- /// the value of the bits, or -1 if not enough bits available.
- ///
- public int GetBits(int bitCount)
- {
- int bits = PeekBits(bitCount);
- if (bits >= 0)
- {
- DropBits(bitCount);
- }
- return bits;
- }
-
- ///
- /// Gets the number of bits available in the bit buffer. This must be
- /// only called when a previous PeekBits() returned -1.
- ///
- ///
- /// the number of bits available.
- ///
- public int AvailableBits
- {
- get
- {
- return bitsInBuffer_;
- }
- }
-
- ///
- /// Gets the number of bytes available.
- ///
- ///
- /// The number of bytes available.
- ///
- public int AvailableBytes
- {
- get
- {
- return windowEnd_ - windowStart_ + (bitsInBuffer_ >> 3);
- }
- }
-
- ///
- /// Skips to the next byte boundary.
- ///
- public void SkipToByteBoundary()
- {
- buffer_ >>= (bitsInBuffer_ & 7);
- bitsInBuffer_ &= ~7;
- }
-
- ///
- /// Returns true when SetInput can be called
- ///
- public bool IsNeedingInput
- {
- get
- {
- return windowStart_ == windowEnd_;
- }
- }
-
- ///
- /// Copies bytes from input buffer to output buffer starting
- /// at output[offset]. You have to make sure, that the buffer is
- /// byte aligned. If not enough bytes are available, copies fewer
- /// bytes.
- ///
- ///
- /// The buffer to copy bytes to.
- ///
- ///
- /// The offset in the buffer at which copying starts
- ///
- ///
- /// The length to copy, 0 is allowed.
- ///
- ///
- /// The number of bytes copied, 0 if no bytes were available.
- ///
- ///
- /// Length is less than zero
- ///
- ///
- /// Bit buffer isnt byte aligned
- ///
- public int CopyBytes(byte[] output, int offset, int length)
- {
- if (length < 0)
- {
- throw new ArgumentOutOfRangeException("length");
- }
-
- if ((bitsInBuffer_ & 7) != 0)
- {
- // bits_in_buffer may only be 0 or a multiple of 8
- throw new InvalidOperationException("Bit buffer is not byte aligned!");
- }
-
- int count = 0;
- while ((bitsInBuffer_ > 0) && (length > 0))
- {
- output[offset++] = (byte)buffer_;
- buffer_ >>= 8;
- bitsInBuffer_ -= 8;
- length--;
- count++;
- }
-
- if (length == 0)
- {
- return count;
- }
-
- int avail = windowEnd_ - windowStart_;
- if (length > avail)
- {
- length = avail;
- }
- System.Array.Copy(window_, windowStart_, output, offset, length);
- windowStart_ += length;
-
- if (((windowStart_ - windowEnd_) & 1) != 0)
- {
- // We always want an even number of bytes in input, see peekBits
- buffer_ = (uint)(window_[windowStart_++] & 0xff);
- bitsInBuffer_ = 8;
- }
- return count + length;
- }
-
- ///
- /// Resets state and empties internal buffers
- ///
- public void Reset()
- {
- buffer_ = 0;
- windowStart_ = windowEnd_ = bitsInBuffer_ = 0;
- }
-
- ///
- /// Add more input for consumption.
- /// Only call when IsNeedingInput returns true
- ///
- /// data to be input
- /// offset of first byte of input
- /// number of bytes of input to add.
- public void SetInput(byte[] buffer, int offset, int count)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException("buffer");
- }
-
- if (offset < 0)
- {
-#if NETCF_1_0
- throw new ArgumentOutOfRangeException("offset");
-#else
- throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
-#endif
- }
-
- if (count < 0)
- {
-#if NETCF_1_0
- throw new ArgumentOutOfRangeException("count");
-#else
- throw new ArgumentOutOfRangeException("count", "Cannot be negative");
-#endif
- }
-
- if (windowStart_ < windowEnd_)
- {
- throw new InvalidOperationException("Old input was not completely processed");
- }
-
- int end = offset + count;
-
- // We want to throw an ArrayIndexOutOfBoundsException early.
- // Note the check also handles integer wrap around.
- if ((offset > end) || (end > buffer.Length))
- {
- throw new ArgumentOutOfRangeException("count");
- }
-
- if ((count & 1) != 0)
- {
- // We always want an even number of bytes in input, see PeekBits
- buffer_ |= (uint)((buffer[offset++] & 0xff) << bitsInBuffer_);
- bitsInBuffer_ += 8;
- }
-
- window_ = buffer;
- windowStart_ = offset;
- windowEnd_ = end;
- }
-
- #region Instance Fields
- private byte[] window_;
- private int windowStart_;
- private int windowEnd_;
-
- private uint buffer_;
- private int bitsInBuffer_;
- #endregion
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/ZipConstants.cs b/src/ImageProcessor/Formats/Png/Zlib/ZipConstants.cs
deleted file mode 100644
index 3ac686aad..000000000
--- a/src/ImageProcessor/Formats/Png/Zlib/ZipConstants.cs
+++ /dev/null
@@ -1,263 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageProcessor.Formats
-{
- using System.Text;
-
- ///
- /// This class contains constants used for Zip format files
- ///
- public static class ZipConstants
- {
- ///
- /// The version made by field for entries in the central header when created by this library
- ///
- ///
- /// This is also the Zip version for the library when comparing against the version required to extract
- /// for an entry.
- public const int VersionMadeBy = 51; // was 45 before AES
-
- ///
- /// The minimum version required to support strong encryption
- ///
- public const int VersionStrongEncryption = 50;
-
- ///
- /// Version indicating AES encryption
- ///
- public const int VERSION_AES = 51;
-
- ///
- /// The version required for Zip64 extensions (4.5 or higher)
- ///
- public const int VersionZip64 = 45;
-
- ///
- /// Size of local entry header (excluding variable length fields at end)
- ///
- public const int LocalHeaderBaseSize = 30;
-
- ///
- /// Size of Zip64 data descriptor
- ///
- public const int Zip64DataDescriptorSize = 24;
-
- ///
- /// Size of data descriptor
- ///
- public const int DataDescriptorSize = 16;
-
- ///
- /// Size of central header entry (excluding variable fields)
- ///
- public const int CentralHeaderBaseSize = 46;
-
- ///
- /// Size of end of central record (excluding variable fields)
- ///
- public const int EndOfCentralRecordBaseSize = 22;
-
- ///
- /// Size of 'classic' cryptographic header stored before any entry data
- ///
- public const int CryptoHeaderSize = 12;
-
- ///
- /// Signature for local entry header
- ///
- public const int LocalHeaderSignature = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);
-
- ///
- /// Signature for spanning entry
- ///
- public const int SpanningSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
-
- ///
- /// Signature for temporary spanning entry
- ///
- public const int SpanningTempSignature = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);
-
- ///
- /// Signature for data descriptor
- ///
- ///
- /// This is only used where the length, Crc, or compressed size isnt known when the
- /// entry is created and the output stream doesnt support seeking.
- /// The local entry cannot be 'patched' with the correct values in this case
- /// so the values are recorded after the data prefixed by this header, as well as in the central directory.
- ///
- public const int DataDescriptorSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
-
- ///
- /// Signature for central header
- ///
- public const int CentralHeaderSignature = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);
-
- ///
- /// Signature for Zip64 central file header
- ///
- public const int Zip64CentralFileHeaderSignature = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);
-
- ///
- /// Signature for Zip64 central directory locator
- ///
- public const int Zip64CentralDirLocatorSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24);
-
- ///
- /// Signature for archive extra data signature (were headers are encrypted).
- ///
- public const int ArchiveExtraDataSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24);
-
- ///
- /// Central header digitial signature
- ///
- public const int CentralHeaderDigitalSignature = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);
-
- ///
- /// End of central directory record signature
- ///
- public const int EndOfCentralDirectorySignature = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);
-
- ///
- /// PCL don't support CodePage so we used Encoding instead of
- ///
- public static Encoding DefaultEncoding { get; set; } = Encoding.UTF8;
-
- ///
- /// Convert a portion of a byte array to a string.
- ///
- ///
- /// Data to convert to string
- ///
- ///
- /// Number of bytes to convert starting from index 0
- ///
- ///
- /// data[0]..data[count - 1] converted to a string
- ///
- public static string ConvertToString(byte[] data, int count)
- {
- if (data == null)
- {
- return string.Empty;
- }
-
- return DefaultEncoding.GetString(data, 0, count);
- }
-
- ///
- /// Convert a byte array to string
- ///
- ///
- /// Byte array to convert
- ///
- ///
- /// dataconverted to a string
- ///
- public static string ConvertToString(byte[] data)
- {
- if (data == null)
- {
- return string.Empty;
- }
-
- return ConvertToString(data, data.Length);
- }
-
- ///
- /// Convert a byte array to string
- ///
- /// The applicable general purpose bits flags
- ///
- /// Byte array to convert
- ///
- /// The number of bytes to convert.
- ///
- /// dataconverted to a string
- ///
- public static string ConvertToStringExt(int flags, byte[] data, int count)
- {
- if (data == null)
- {
- return string.Empty;
- }
-
- if ((flags & (int)GeneralBitFlags.UnicodeText) != 0)
- {
- return Encoding.UTF8.GetString(data, 0, count);
- }
- else
- {
- return ConvertToString(data, count);
- }
- }
-
- ///
- /// Convert a byte array to string
- ///
- /// The applicable general purpose bits flags
- /// Byte array to convert
- ///
- /// dataconverted to a string
- ///
- public static string ConvertToStringExt(int flags, byte[] data)
- {
- if (data == null)
- {
- return string.Empty;
- }
-
- if ((flags & (int)GeneralBitFlags.UnicodeText) != 0)
- {
- return Encoding.UTF8.GetString(data, 0, data.Length);
- }
- else
- {
- return ConvertToString(data, data.Length);
- }
- }
-
- ///
- /// Convert a string to a byte array
- ///
- ///
- /// String to convert to an array
- ///
- /// Converted array
- public static byte[] ConvertToArray(string str)
- {
- if (str == null)
- {
- return new byte[0];
- }
-
- return DefaultEncoding.GetBytes(str);
- }
-
- ///
- /// Convert a string to a byte array
- ///
- /// The applicable general purpose bits flags
- ///
- /// String to convert to an array
- ///
- /// Converted array
- public static byte[] ConvertToArray(int flags, string str)
- {
- if (str == null)
- {
- return new byte[0];
- }
-
- if ((flags & (int)GeneralBitFlags.UnicodeText) != 0)
- {
- return Encoding.UTF8.GetBytes(str);
- }
-
- return ConvertToArray(str);
- }
- }
-}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/NewFolder/ZlibInputStream.cs b/src/ImageProcessor/Formats/Png/Zlib/ZlibInputStream.cs
similarity index 98%
rename from src/ImageProcessor/Formats/Png/Zlib/NewFolder/ZlibInputStream.cs
rename to src/ImageProcessor/Formats/Png/Zlib/ZlibInputStream.cs
index 129042bda..bcbd5d3bd 100644
--- a/src/ImageProcessor/Formats/Png/Zlib/NewFolder/ZlibInputStream.cs
+++ b/src/ImageProcessor/Formats/Png/Zlib/ZlibInputStream.cs
@@ -5,7 +5,7 @@ namespace ImageProcessor.Formats
using System.IO;
using System.IO.Compression;
- internal class ZlibInputStream : Stream
+ internal sealed class ZlibInputStream : Stream
{
///
/// A value indicating whether this instance of the given entity has been disposed.
@@ -146,7 +146,7 @@ namespace ImageProcessor.Formats
for (int i = 0; i < 4; i++)
{
// we dont really check/use this
- this.crcread[i] = (byte)rawStream.ReadByte();
+ this.crcread[i] = (byte)this.rawStream.ReadByte();
}
}
diff --git a/src/ImageProcessor/Formats/Png/Zlib/NewFolder/ZlibOutputStream.cs b/src/ImageProcessor/Formats/Png/Zlib/ZlibOutputStream.cs
similarity index 95%
rename from src/ImageProcessor/Formats/Png/Zlib/NewFolder/ZlibOutputStream.cs
rename to src/ImageProcessor/Formats/Png/Zlib/ZlibOutputStream.cs
index 258c13f0e..9af156d06 100644
--- a/src/ImageProcessor/Formats/Png/Zlib/NewFolder/ZlibOutputStream.cs
+++ b/src/ImageProcessor/Formats/Png/Zlib/ZlibOutputStream.cs
@@ -1,11 +1,15 @@
-
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
namespace ImageProcessor.Formats
{
using System;
using System.IO;
using System.IO.Compression;
- internal class ZlibOutputStream : Stream
+ internal sealed class ZlibOutputStream : Stream
{
///
/// The raw stream containing the uncompressed image data.
@@ -48,8 +52,8 @@ namespace ImageProcessor.Formats
// 4-bit information field depending on the compression method.
// bits 0 to 3 CM Compression method
// bits 4 to 7 CINFO Compression info
- // 0 1
//
+ // 0 1
// +---+---+
// |CMF|FLG|
// +---+---+
@@ -95,8 +99,6 @@ namespace ImageProcessor.Formats
level = CompressionLevel.NoCompression;
}
- // I must create with leaveopen=true always and do the closing myself, because MS implementation
- // of DeflateStream: I cant force a flush of the underlying stream without closing.
this.deflateStream = new DeflateStream(this.rawStream, level, true);
}
@@ -181,7 +183,7 @@ namespace ImageProcessor.Formats
}
else {
- // Second hack: empty input?
+ // Hack: empty input?
this.rawStream.WriteByte(3);
this.rawStream.WriteByte(0);
}
diff --git a/tests/ImageProcessor.Tests/Processors/Formats/EncoderDecoderTests.cs b/tests/ImageProcessor.Tests/Processors/Formats/EncoderDecoderTests.cs
index baf56ed3b..374f00afb 100644
--- a/tests/ImageProcessor.Tests/Processors/Formats/EncoderDecoderTests.cs
+++ b/tests/ImageProcessor.Tests/Processors/Formats/EncoderDecoderTests.cs
@@ -17,10 +17,10 @@
Directory.CreateDirectory("TestOutput/Encode");
}
- foreach (FileInfo file in new DirectoryInfo("TestOutput/Encode").GetFiles())
- {
- file.Delete();
- }
+ //foreach (FileInfo file in new DirectoryInfo("TestOutput/Encode").GetFiles())
+ //{
+ // file.Delete();
+ //}
foreach (string file in Files)
{
diff --git a/tests/ImageProcessor.Tests/TestImages/Formats/Png/mountain.png.REMOVED.git-id b/tests/ImageProcessor.Tests/TestImages/Formats/Png/mountain.png.REMOVED.git-id
deleted file mode 100644
index e10578b3c..000000000
--- a/tests/ImageProcessor.Tests/TestImages/Formats/Png/mountain.png.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-e51bffc5ceb300a70039c9c3ce4542eff47925ea
\ No newline at end of file