//Compress integer array into BitStream public static BitStreamFIFO Compress(int[] source) { //Compress the array of integers using all different compression techniques, where possible at the same time BitStreamFIFO[] compressionTechniques = new BitStreamFIFO[2]; Parallel.For(0, compressionTechniques.Length, (i, state) => { switch (i) { //Huffmann: generate a dictionary of all used integer values where more frequent values have a code with less bits case 0: compressionTechniques[i] = HuffmanIntArrayCompressor.Compress(source); break; //Variable int length: save smaller integers with less bits than bigger integers case 1: compressionTechniques[i] = VaryingIntLengthIntArrayCompressor.Compress(source); break; //To add a compression technique, add a new case like the existing ones and increase the length of new byte[??][] } }); //Choose the smallest compression type //Initialize int smallestID = 0; //The ID of the smallest compression type int smallestSize = int.MaxValue; //The size ofthe smallest compression type: int.MaxValue is assigned to make sure that the first compression to be checked will be smaaller than this value //Loop trough all saved compression techniques for (int i = 0; i < compressionTechniques.Length; i++) { //If the current technique is smaller than the smallest technique which has been checked if (compressionTechniques[i].Length < smallestSize) { //Mark this technique as smallest smallestSize = compressionTechniques[i].Length; smallestID = i; } } //Create a new BitStream to write necessary information for the decompressor BitStreamFIFO compressionInfo = new BitStreamFIFO(); //Calculate the amount of bits needed to save the total length in bits of the compressed data int lengthSaveLength = (int)Math.Ceiling(Math.Log(smallestSize, 2) / 8); //Write data to the compression info compressionInfo.Write(smallestID, 2); //The compression technique used compressionInfo.Write(lengthSaveLength, 6); //The amount of bits needed to save the total length in bits of the compressed data compressionInfo.Write(smallestSize, lengthSaveLength * 8); //The total length in bits of the compressed data //Merge the info about the compression type with the compressed data & return return(BitStreamFIFO.Merge(compressionInfo, compressionTechniques[smallestID])); }
//Compress aBitmap into byte array public static byte[] Compress(AccessibleBitmap source) { //Initialize List <int> distances = new List <int>(); //A list containing all the lenghts of same pixels List <int> pixels = new List <int>(); //A list containing all the pixels that correspond to the lengths in 'distances' list int tempDistance = -1; //The length of one run of bits with the same value, while it is not saved yet: -1 because it will be increased before the first check byte[] lastPixel = source.GetPixel(0, 0); //The pixel of the last checked pixel, to compare with the current pixel: set value to the value of the first pixel so the first check will succeed //Loop trough all lines of pixels for (int y = 0; y < source.height; y++) { //Loop trough all pixels in this line for (int x = 0; x < source.width; x++) { //Take value of the current pixel byte[] currentPixel = source.GetPixel(x, y); //If the value of the bit of this pixel matches the value of the bit of the previous pixel if (currentPixel.SequenceEqual(lastPixel)) { //Values are the same, so increase current run tempDistance++; } else { //Values are not the same, so save the run distances.Add(tempDistance); pixels.AddRange(Array.ConvertAll(lastPixel, b => (int)b)); //Set the bit value for the next comparison to the bit value of this pixel lastPixel = currentPixel; //Reset the run length for the new run tempDistance = 0; } } } //Save the last run becouse this never happens in the loop distances.Add(tempDistance); pixels.AddRange(Array.ConvertAll(lastPixel, b => (int)b)); //Compress the array of run lengths using different techniques BitStreamFIFO pixelStream = VaryingIntArrayCompressor.Compress(pixels.ToArray()); //Compress the array of run lengths using different techniques BitStreamFIFO lengthStream = VaryingIntArrayCompressor.Compress(distances.ToArray()); //Combine the compressed data of the runs with the compressed data of the pixel values, then return the BitStream return(BitStreamFIFO.Merge(pixelStream, lengthStream).ToByteArray()); }
//Compress aBitmap into byte array public static BitStreamFIFO Compress(AccessibleBitmapBitwise source, int bitLayer) { //Initialize List <int> distances = new List <int>(); //A list containing all the lenghts of same bits int tempDistance = -1; //The length of one run of bits with the same value, while it is not saved yet: -1 becouse it will be increased before the first check bool lastVal = source.GetPixelBit(0, 0, bitLayer); //The bit value of the last checked pixel, to compare with the current pixel: set value to the value of the first pixel so the first check will succeed //Loop trough all lines of pixels for (int y = 0; y < source.height; y++) { //Loop trough all pixels in this line for (int x = 0; x < source.width; x++) { //Take value of the current pixel bool currentBool = source.GetPixelBit(x, y, bitLayer); //If the value of the bit of this pixel matches the value of the bit of the previous pixel if (currentBool == lastVal) { //Values are the same, so increase current run tempDistance++; } else { //Values are not the same, so save the run distances.Add(tempDistance); //Set the bit value for the next comparison to the bit value of this pixel lastVal = currentBool; //Reset the run length for the new run tempDistance = 0; } } } //Save the last run becouse this never happens in the loop distances.Add(tempDistance); //Save the bit value of the first pixel, because the decompressor needs to know this bool initialVal = source.GetPixelBit(0, 0, bitLayer); //Compress the array of run lengths using different techniques BitStreamFIFO bitStream = VaryingIntArrayCompressor.Compress(distances.ToArray()); //Combine the inititial bit value with the compressed data of the runs, then return the BitStream return(BitStreamFIFO.Merge(new BitStreamFIFO(new bool[] { initialVal }), bitStream)); }
//Compress aBitmap into byte array public static BitStreamFIFO Compress(AccessibleBitmapBitwise source, int bitLayer) { //Initialize vars BitStreamFIFO bitStream = new BitStreamFIFO(); List <int> distances = new List <int>(); int tempDistance = -1; bool lastVal = source.GetPixelBit(0, 0, bitLayer); //Iterate trough pixels for (int y = 0; y < source.height; y++) { for (int x = 0; x < source.width; x++) { //Take value of pixel & compare with previous value bool currentBool = source.GetPixelBit(x, y, bitLayer); if (currentBool == lastVal) { //Values are the same, so increase current run tempDistance++; } else { //Values are not the same, so save the run and create a new one distances.Add(tempDistance); lastVal = currentBool; tempDistance = 0; } } } //Save the last run becouse this never happens in the loop distances.Add(tempDistance); bool initialVal = source.GetPixelBit(0, 0, bitLayer); bitStream.Write(initialVal); BitStreamFIFO output = BitStreamFIFO.Merge(bitStream, VaryingIntArrayCompressor.Compress(distances.ToArray())); return(output); }
//Compress aBitmap into byte array public static byte[] Compress(AccessibleBitmapBytewise source, int byteLayer) { //Loop trough all layers of bits, where possible at the same time AccessibleBitmapBitwise aBitmap = new AccessibleBitmapBitwise(source); BitStreamFIFO[] byteLayers = new BitStreamFIFO[8]; Parallel.For(byteLayer * 8, byteLayer * 8 + 8, (z, state) => //for(int z = byteLayer * 8; z < byteLayer * 8 + 8; z++) { //Compress image using all different compression techniques, where possible at the same time BitStreamFIFO[] compressionTechniques = new BitStreamFIFO[4]; Parallel.For(0, compressionTechniques.Length, (i, state2) => { switch (i) { //Uncompressed (only used if no compression technique is smaller) case 0: compressionTechniques[i] = UncompressedBitmapCompressorBitwise.Compress(aBitmap, z); break; //Compress bit channel as an integer array using several techniques, using 8-bit integers case 1: compressionTechniques[i] = ByteArrayCompressorBitwise.Compress(aBitmap, z); break; //Run length compression: save the length of a sequence of bit values instead of saving them seperately case 2: compressionTechniques[i] = RunLengthEncodingCompressorBitwise.Compress(aBitmap, z); break; //Run length compression vertical: run length compression, but scan the pixels horizontally, becouse with some images this yields better results case 3: compressionTechniques[i] = RunLengthEncodingCompressorVerticalBitwise.Compress(aBitmap, z); break; //To add a compression technique, add a new case like the existing ones and increase the length of new byte[??][] } }); //Choose the smallest compression type //Initialize int smallestID = 0; //The ID of the smallest compression type int smallestSize = int.MaxValue; //The size ofthe smallest compression type: int.MaxValue is assigned to make sure that the first compression to be checked will be smaaller than this value //Loop trough all saved compression techniques for (int i = 0; i < compressionTechniques.Length; i++) { //If the current technique is smaller than the smallest technique which has been checked if (compressionTechniques[i].Length < smallestSize) { //Mark this technique as smallest smallestSize = compressionTechniques[i].Length; smallestID = i; } } //Merge the number of the compression type of this layer with corresponding bitStream BitStreamFIFO tmpStream = new BitStreamFIFO(); tmpStream.Write(smallestID, 3); //This 3-bit integer indicates which technique the decompressor should use, and should be before the image data byteLayers[z % 8] = BitStreamFIFO.Merge(tmpStream, compressionTechniques[smallestID]); }); //Combine all bitstreams & convert the result to a byte array byte[] outputStream = BitStreamFIFO.Merge(byteLayers).ToByteArray(); //Return the data of all the bit channels combined return(outputStream); }