⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 deflate.cs

📁 PDF文件格式解析库源代码
💻 CS
字号:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using QiHe.CodeLib.Compress.DeflateFormat;

namespace QiHe.CodeLib.Compress
{
    public partial class Deflate
    {
        public static byte[] Compress(byte[] data)
        {
            MemoryStream input = new MemoryStream(data);
            MemoryStream output = new MemoryStream();
            Compress(input, output);
            return output.ToArray();
        }

        public static void Compress(Stream input, Stream output)
        {
            Compress(input, output, CompressionOption.Smaller);
        }

        public static void Compress(Stream input, Stream output, CompressionOption option)
        {
            BitStream outputStream = new BitStream(output);
            CompressedItemGroup group = new CompressedItemGroup();
            MultiSet<int> alphabetSet = new MultiSet<int>();
            MultiSet<int> distanceSet = new MultiSet<int>();
            float ratio = 8;
            bool decrease = false;
            bool first = true;
            foreach (CompressedItem item in Compressor.AnalyzeItems(input, option))
            {
                group.Items.Add(item);
                if (item is LiteralByte)
                {
                    alphabetSet.Add(((LiteralByte)item).Value);
                }
                else if (item is LengthDistancePair)
                {
                    LengthDistancePair pair = item as LengthDistancePair;
                    alphabetSet.Add(DeflateCoding.Length[pair.Length].Code);
                    distanceSet.Add(DeflateCoding.Distance[pair.Distance].Code);
                }

                if (group.Items.Count % 200 == 0)
                {

                    float count = (float)(group.Items.Count);
                    float new_ratio = EstimateCompressRatio(alphabetSet, count);

                    if (new_ratio > ratio && decrease)
                    {
                        if (!first)
                        {
                            //TraceTool.MultiColPage.Debug.Send(String.Format("{0}\t{1}", count, ratio));

                            alphabetSet.Add(DeflateCoding.EndOfBlock);
                            Encode(group, alphabetSet, distanceSet, outputStream);
                            group.Items.Clear();
                            alphabetSet.Clear();
                            distanceSet.Clear();
                            new_ratio = 8;
                            decrease = false;
                            first = true;
                        }
                        else
                        {
                            decrease = false;
                            first = false;
                        }
                    }
                    if (new_ratio < ratio && !decrease)
                    {
                        decrease = true;
                    }
                    ratio = new_ratio;
                }
            }

            alphabetSet.Add(DeflateCoding.EndOfBlock);
            group.IsFinal = true;

            Encode(group, alphabetSet, distanceSet, outputStream);
            outputStream.Flush();
        }

        private static void Encode(CompressedItemGroup group, MultiSet<int> alphabetSet, MultiSet<int> distanceSet, BitStream output)
        {
            HuffmanCodes huffmanCodes = new HuffmanCodes(alphabetSet, distanceSet);
            int dynamicSize = huffmanCodes.CalculateBlockSize();
            int defaultSize = huffmanCodes.CalculateDefaultBlockSize();

            if (dynamicSize >= defaultSize)
            {
                WriteDefaultCodedBlock(group, output);
            }
            else
            {
                WriteDynamicCodedBlock(group, output, huffmanCodes);
            }
        }

        private static float EstimateCompressRatio(MultiSet<int> alphabetSet, float count)
        {
            HuffmanTree alphabetHuffmanCode = HuffmanTree.FromSymbolWeights(alphabetSet, 15);
            int wpl = alphabetHuffmanCode.WeightedPathLength;
            float new_ratio = (float)Math.Round((wpl + alphabetSet.Count * 7) / count, 2);
            return new_ratio;
        }

        private static void Encode(CompressedItemGroup group, BitStream output)
        {
            MultiSet<int> alphabetSet = new MultiSet<int>();
            MultiSet<int> distanceSet = new MultiSet<int>();
            foreach (CompressedItem item in group.Items)
            {
                if (item is LiteralByte)
                {
                    alphabetSet.Add(((LiteralByte)item).Value);
                }
                else if (item is LengthDistancePair)
                {
                    LengthDistancePair pair = item as LengthDistancePair;
                    alphabetSet.Add(DeflateCoding.Length[pair.Length].Code);
                    distanceSet.Add(DeflateCoding.Distance[pair.Distance].Code);
                }

            }
            alphabetSet.Add(DeflateCoding.EndOfBlock);

            if (distanceSet.Count == 0)
            {
                WriteDefaultCodedBlock(group, output);
            }
            else
            {
                HuffmanCodes huffmanCodes = new HuffmanCodes(alphabetSet, distanceSet);
                WriteDynamicCodedBlock(group, output, huffmanCodes);
            }
        }

        private static void WriteCopiedBlock(CompressedItemGroup group, BitStream output)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private static void WriteDefaultCodedBlock(CompressedItemGroup group, BitStream output)
        {
            output.WriteBit(group.IsFinal);
            output.WriteBits((int)BlockType.FixedHuffmanCodes, 2);
            WriteBlockContent(group, output, HuffmanCodes.Default);
        }

        private static void WriteDynamicCodedBlock(CompressedItemGroup group, BitStream output, HuffmanCodes huffmanCodes)
        {
            output.WriteBit(group.IsFinal);
            output.WriteBits((int)BlockType.DynamicHuffmanCodes, 2);

            huffmanCodes.Encode(output);

            WriteBlockContent(group, output, huffmanCodes);
        }

        private static void WriteBlockContent(CompressedItemGroup group, BitStream output, HuffmanCodes huffmanCodes)
        {
            foreach (CompressedItem item in group.Items)
            {
                if (item is LiteralByte)
                {
                    LiteralByte literal = item as LiteralByte;
                    huffmanCodes.WriteLiteral(output, literal.Value);
                }
                else if (item is LengthDistancePair)
                {
                    LengthDistancePair pair = item as LengthDistancePair;
                    huffmanCodes.WriteLength(output, pair.Length);
                    huffmanCodes.WriteDistance(output, pair.Distance);
                }
            }

            huffmanCodes.WriteLiteral(output, DeflateCoding.EndOfBlock);
        }
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -