mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-09-20 03:17:57 +08:00
write valid zlib stream for flate
since c# only produces a deflate stream when compressing it is necessary to provide the header and footer bytes to convert this to a valid zlib stream. this involves setting the correct 2 bytes for the header and appending a 4 byte adler checksum for the uncompressed data after the compressed data stream.
This commit is contained in:
@@ -27,6 +27,9 @@
|
|||||||
private const int DefaultBitsPerComponent = 8;
|
private const int DefaultBitsPerComponent = 8;
|
||||||
private const int DefaultColumns = 1;
|
private const int DefaultColumns = 1;
|
||||||
|
|
||||||
|
private const byte Deflate32KbWindow = 120;
|
||||||
|
private const byte ChecksumBits = 1;
|
||||||
|
|
||||||
private readonly IDecodeParameterResolver decodeParameterResolver;
|
private readonly IDecodeParameterResolver decodeParameterResolver;
|
||||||
private readonly IPngPredictor pngPredictor;
|
private readonly IPngPredictor pngPredictor;
|
||||||
private readonly ILog log;
|
private readonly ILog log;
|
||||||
@@ -106,17 +109,45 @@
|
|||||||
|
|
||||||
public byte[] Encode(Stream input, DictionaryToken streamDictionary, int index)
|
public byte[] Encode(Stream input, DictionaryToken streamDictionary, int index)
|
||||||
{
|
{
|
||||||
var resx = new List<byte>{ 120, 156 };
|
const int headerLength = 2;
|
||||||
using (var output = new MemoryStream())
|
const int checksumLength = 4;
|
||||||
using (var flater = new DeflateStream(output, CompressionMode.Compress, true))
|
|
||||||
{
|
|
||||||
input.CopyTo(flater);
|
|
||||||
flater.Close();
|
|
||||||
|
|
||||||
resx.AddRange(output.ToArray());
|
byte[] data;
|
||||||
|
using (var temp = new MemoryStream())
|
||||||
|
{
|
||||||
|
input.CopyTo(temp);
|
||||||
|
data = temp.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
return resx.ToArray();
|
using (var compressStream = new MemoryStream())
|
||||||
|
using (var compressor = new DeflateStream(compressStream, CompressionLevel.Fastest))
|
||||||
|
{
|
||||||
|
compressor.Write(data, 0, data.Length);
|
||||||
|
compressor.Close();
|
||||||
|
|
||||||
|
var compressed = compressStream.ToArray();
|
||||||
|
|
||||||
|
var result = new byte[headerLength + compressed.Length + checksumLength];
|
||||||
|
|
||||||
|
// Write the ZLib header.
|
||||||
|
result[0] = Deflate32KbWindow;
|
||||||
|
result[1] = ChecksumBits;
|
||||||
|
|
||||||
|
// Write the compressed data.
|
||||||
|
Array.Copy(compressed, 0, result, headerLength, compressed.Length);
|
||||||
|
|
||||||
|
// Write Checksum of raw data.
|
||||||
|
var checksum = Adler32Checksum.Calculate(data);
|
||||||
|
|
||||||
|
var offset = headerLength + compressed.Length;
|
||||||
|
|
||||||
|
result[offset++] = (byte)(checksum >> 24);
|
||||||
|
result[offset++] = (byte)(checksum >> 16);
|
||||||
|
result[offset++] = (byte)(checksum >> 8);
|
||||||
|
result[offset] = (byte)(checksum >> 0);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
35
src/UglyToad.PdfPig/Util/Adler32Checksum.cs
Normal file
35
src/UglyToad.PdfPig/Util/Adler32Checksum.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
namespace UglyToad.PdfPig.Util
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to calculate the Adler-32 checksum used for ZLIB data in accordance with
|
||||||
|
/// RFC 1950: ZLIB Compressed Data Format Specification.
|
||||||
|
/// </summary>
|
||||||
|
public static class Adler32Checksum
|
||||||
|
{
|
||||||
|
// Both sums (s1 and s2) are done modulo 65521.
|
||||||
|
private const int AdlerModulus = 65521;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculate the Adler-32 checksum for some data.
|
||||||
|
/// </summary>
|
||||||
|
public static int Calculate(IEnumerable<byte> data)
|
||||||
|
{
|
||||||
|
// s1 is the sum of all bytes.
|
||||||
|
var s1 = 1;
|
||||||
|
|
||||||
|
// s2 is the sum of all s1 values.
|
||||||
|
var s2 = 0;
|
||||||
|
|
||||||
|
foreach (var b in data)
|
||||||
|
{
|
||||||
|
s1 = (s1 + b) % AdlerModulus;
|
||||||
|
s2 = (s1 + s2) % AdlerModulus;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Adler-32 checksum is stored as s2*65536 + s1.
|
||||||
|
return s2 * 65536 + s1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user