//Decompress byte array into aBitmap with help of width, length and bitdepth public static AccessibleBitmapBytewise Decompress(byte[] inBytes, AccessibleBitmapBytewise inBitmap, out byte[] restBytes, int byteLayer) { //Create a BitStreamFIFO class from the incoming bytes, becouse the decompressor for integer arrays uses it BitStreamFIFO layerBits = new BitStreamFIFO(inBytes); //Decompress the incoming data to an array of integers int[] layerByteArray = VaryingIntArrayCompressor.Decompress(ref layerBits); //Add the data from the array of integers to the incoming bitmap //Loop trough all lines of pixels for (int y = 0; y < inBitmap.height; y++) { //Loop trough all pixels in this line for (int x = 0; x < inBitmap.width; x++) { //Write the integer of this channel from the correct position in the input array to the current pixel inBitmap.SetPixelByte(x, y, byteLayer, (byte)layerByteArray[y * inBitmap.width + x]); } } //Remove the bytes used for this channel from the incoming byte array and pass the rest of them to the next channel restBytes = new byte[layerBits.Length / 8]; Array.Copy(inBytes, inBytes.Length - restBytes.Length, restBytes, 0, restBytes.Length); //Return the modified bitmap so the rest of the channels can be added to complete it return(inBitmap); }
public AccessibleBitmapBitwise(AccessibleBitmapBytewise aBitmap) { width = aBitmap.width; height = aBitmap.height; pixelBytes = aBitmap.pixelBytes; byte[] tmpBytes = aBitmap.GetRawPixelBytes(); boolArray = new bool[tmpBytes.Length * 8]; new BitArray(tmpBytes).CopyTo(boolArray, 0); }
//Decompress byte array into aBitmap with help of width, length and bitdepth public static AccessibleBitmap Decompress(byte[] source, int width, int height, int pixelBytes) { //Create a empty AccessibleBitmapBytewise class with the correct dimensions and color channels AccessibleBitmapBytewise outputBitmap = new AccessibleBitmapBytewise(new AccessibleBitmap(width, height, pixelBytes)); //Initialize byte[] inBytes; //Stores the bytes to feed to the decompressor byte[] outBytes = source; //Stores the bytes which are left by the previous decompressed channel: starts with all the input data //Loop trough all color channels for (int i = 0; i < pixelBytes; i++) { //Read compression type from outBytes & copy the rest of them to inBytes so they can be used for the next channel int compressionType = outBytes[0]; inBytes = new byte[outBytes.Length - 1]; Array.Copy(outBytes, 1, inBytes, 0, inBytes.Length); //Decompress using the correct compression type switch (compressionType) { //Uncompressed case 0: outputBitmap = UncompressedBitmapCompressorBytewise.Decompress(inBytes, outputBitmap, out outBytes, i); break; //Individual compressed bit channels added together case 1: outputBitmap = BitLayerVaryingCompressor.Decompress(inBytes, outputBitmap, out outBytes, i); break; //Color channel compressed as integers case 2: outputBitmap = ByteArrayCompressorBytewise.Decompress(inBytes, outputBitmap, out outBytes, i); break; //Run length compression case 3: outputBitmap = RunLengthEncodingCompressorBytewise.Decompress(inBytes, outputBitmap, out outBytes, i); break; //Run length encoding vertical case 4: outputBitmap = RunLengthEncodingCompressorVerticalBytewise.Decompress(inBytes, outputBitmap, out outBytes, i); break; //To add a decompression type add a new case like the existing ones //Unknown compression type: error default: throw new Exception("Unexisting compression type"); } } return(outputBitmap.GetAccessibleBitmap()); }
//Decompress byte array into aBitmap with help of width, length and bitdepth public static AccessibleBitmapBytewise Decompress(byte[] inBytes, AccessibleBitmapBytewise inBitmap, out byte[] restBytes, int byteLayer) { //Create a AccessibleBitmapbitwise class from the incoming AccessibleBitmapbytewise class, for better access to individual bits AccessibleBitmapBitwise outputBitmap = new AccessibleBitmapBitwise(inBitmap); //Create a BitStreamFIFO class from the incoming bytes, to feed into the decompression algorithms BitStreamFIFO bitStream = new BitStreamFIFO(inBytes); //Loop trough all bit layers of current byte layer for (int i = byteLayer * 8; i < byteLayer * 8 + 8; i++) { //Read compression type as a 3-bit integer int compressionType = bitStream.ReadInt(3); //Decompress using the correct compression type switch (compressionType) { //Uncompressed case 0: outputBitmap = UncompressedBitmapCompressorBitwise.Decompress(bitStream, outputBitmap, out bitStream, i); break; //Bit channel compressed as 8-bit integers case 1: outputBitmap = ByteArrayCompressorBitwise.Decompress(bitStream, outputBitmap, out bitStream, i); break; //Run length encoding case 2: outputBitmap = RunLengthEncodingCompressorBitwise.Decompress(bitStream, outputBitmap, out bitStream, i); break; //Run length encoding vertical case 3: outputBitmap = RunLengthEncodingCompressorVerticalBitwise.Decompress(bitStream, outputBitmap, out bitStream, i); break; //To add a decompression type add a new case like the existing ones //Unknown compression type: error default: throw new Exception("Unexisting compression type"); } } //Remove the bytes used for this channel from the incoming byte array and pass the rest of them to the next channel restBytes = new byte[bitStream.Length / 8]; Array.Copy(inBytes, inBytes.Length - (bitStream.Length / 8), restBytes, 0, restBytes.Length); //Return the modified bitmap as AccessibleBitmapbytewise so the rest of the channels can be added to complete it return(new AccessibleBitmapBytewise(outputBitmap.GetAccessibleBitmap())); }
//Compress aBitmap into byte array public static byte[] Compress(AccessibleBitmapBytewise source, int byteLayer) { //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 becouse it will be increased before the first check byte lastPixel = source.GetPixelByte(0, 0, byteLayer); //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.GetPixelByte(x, y, byteLayer); //If the value of the bit of this pixel matches the value of the bit of the previous pixel if (currentPixel == lastPixel) { //Values are the same, so increase current run tempDistance++; } else { //Values are not the same, so save the run distances.Add(tempDistance); pixels.Add(lastPixel); //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.Add(lastPixel); //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()); }
//Decompress byte array into aBitmap with help of width, length and bitdepth public static AccessibleBitmapBytewise Decompress(byte[] inBytes, AccessibleBitmapBytewise inBitmap, out byte[] restBytes, int byteLayer) { //Create a BitStream from the input bytes becouse the decompress functions need this as input BitStreamFIFO bitStream = new BitStreamFIFO(inBytes); //Decompress the BitStream to a queue of integers for the lengths Queue <int> pixels = new Queue <int>(VaryingIntArrayCompressor.Decompress(ref bitStream)); //Decompress the BitStream to a queue of integers for the pixel values Queue <int> runs = new Queue <int>(VaryingIntArrayCompressor.Decompress(ref bitStream)); //Initialize int pixelsToGo = runs.Dequeue() + 1; //The amount of pixels that should be written before the next run starts byte currentPixel = (byte)pixels.Dequeue(); //The pixel value of the current run: initialize with the first pixel value //Loop trough all lines of pixels for (int y = 0; y < inBitmap.height; y++) { //Loop trough all pixels in this line for (int x = 0; x < inBitmap.width; x++) { //Set the bit of the current pixel to the value of the current run inBitmap.SetPixelByte(x, y, byteLayer, currentPixel); //Decrease the length of the current run pixelsToGo--; //If the end of the run has been reached if (pixelsToGo == 0 && (x * y != (inBitmap.height - 1) * (inBitmap.width - 1))) { //Read the new run length from the BitStream pixelsToGo = runs.Dequeue() + 1; //Take a byte from the queue of pixel values to put in the current channel currentPixel = (byte)pixels.Dequeue(); } } } //Remove the bytes used for this channel from the incoming byte array and pass the rest of them to the next channel restBytes = new byte[bitStream.Length / 8]; Array.Copy(inBytes, inBytes.Length - restBytes.Length, restBytes, 0, restBytes.Length); //Return the image as aBitmap return(inBitmap); }
//Compress aBitmap into byte array public static byte[] Compress(AccessibleBitmapBytewise source, int byteLayer) { //Create byte array with a size equal to the amount of pixels in the image byte[] output = new byte[source.width * source.height]; //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++) { //Write the byte of this channel from the current pixel to the correct position in the output array output[y * source.width + x] = source.GetPixelByte(x, y, byteLayer); } } //Return all bytes of this channel return(output); }
//Compress aBitmap into byte array public static byte[] Compress(AccessibleBitmapBytewise source, int byteLayer) { //Create int array with a size equal to the amount of pixels in the image int[] layerByteArray = new int[source.width * source.height]; //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++) { //Write the byte of this channel from the current pixel to the correct position in the output array layerByteArray[y * source.width + x] = source.GetPixelByte(x, y, byteLayer); } } //Compress the obtained array of integers using different techniques byte[] outputArray = VaryingIntArrayCompressor.Compress(layerByteArray).ToByteArray(); //Return the output array return(outputArray); }
//Decompress byte array into aBitmap with help of width, length and bitdepth public static AccessibleBitmapBytewise Decompress(byte[] inBytes, AccessibleBitmapBytewise inBitmap, out byte[] restBytes, int byteLayer) { //Add the data from this stream to the incoming bitmap //Loop trough all lines of pixels for (int y = 0; y < inBitmap.height; y++) { //Loop trough all pixels in this line for (int x = 0; x < inBitmap.width; x++) { //Write the byte of this channel from the correct position in the input array to the current pixel inBitmap.SetPixelByte(x, y, byteLayer, inBytes[y * inBitmap.width + x]); } } //Remove the bytes used for this channel from the incoming byte array and pass the rest of them to the next channel restBytes = new byte[inBytes.Length - (inBitmap.width * inBitmap.height)]; Array.Copy(inBytes, inBitmap.width * inBitmap.height, restBytes, 0, restBytes.Length); //Return the modified bitmap so the rest of the channels can be added to complete it return(inBitmap); }
//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); }
//Compress aBitmap into byte array public static byte[] Compress(AccessibleBitmap source) { //Loop trough all layers of bytes, where possible at the same time AccessibleBitmapBytewise aBitmap = new AccessibleBitmapBytewise(source); byte[][] byteLayers = new byte[source.pixelBytes][]; Parallel.For(0, source.pixelBytes, (z, state) => //for(int z = 0; z < source.pixelBytes; z++) { //Compress image using all different compression techniques, where possible at the same time byte[][] compressionTechniques = new byte[5][]; Parallel.For(0, compressionTechniques.Length, (i, state2) => { switch (i) { //Uncompressed (only used if no compression technique is smaller) case 0: compressionTechniques[i] = UncompressedBitmapCompressorBytewise.Compress(aBitmap, z); break; //Split color channel in its bit channels and apply compression over them case 1: compressionTechniques[i] = BitLayerVaryingCompressor.Compress(aBitmap, z); break; //Compress color channel as an integer array using several techniques case 2: compressionTechniques[i] = ByteArrayCompressorBytewise.Compress(aBitmap, z); break; //Run length compression: save the length of a sequence of pixels with the same color instead of saving them seperately case 3: compressionTechniques[i] = RunLengthEncodingCompressorBytewise.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 4: compressionTechniques[i] = RunLengthEncodingCompressorVerticalBytewise.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 byte array byteLayers[z] = new byte[compressionTechniques[smallestID].Length + 1]; byteLayers[z][0] = (byte)smallestID; //This byte indicates which technique the decompressor should use, and should be before the image data Array.Copy(compressionTechniques[smallestID], 0, byteLayers[z], 1, compressionTechniques[smallestID].Length); }); //Combine all byte layers by looping trough all of them and adding them after each other List <byte> output = new List <byte>(); foreach (byte[] b in byteLayers) { output.AddRange(b); } //Return the data of all the color channels combined return(output.ToArray()); }