Exemple #1
0
            public AccessibleBitmap GetAccessibleBitmap()
            {
                AccessibleBitmap aBitmap = new AccessibleBitmap(width, height, pixelBytes);

                aBitmap.SetRawPixelBytes(byteArray);
                return(aBitmap);
            }
Exemple #2
0
 public AccessibleBitmapBytewise(AccessibleBitmap aBitmap)
 {
     width      = aBitmap.width;
     height     = aBitmap.height;
     pixelBytes = aBitmap.pixelBytes;
     byteArray  = aBitmap.GetRawPixelBytes();
 }
        //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 BitStream from the input bytes becouse the decompress functions need this as input
            BitStreamFIFO bitStream = new BitStreamFIFO(source);

            //Create an empty bitmap with the correct dimensions, where the decompressed pixels will be written to
            AccessibleBitmap aBitmap = new AccessibleBitmap(width, height, pixelBytes);

            //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 = new byte[pixelBytes]; //The pixel value of the current run: initialize with the correct amount of channels

            //Loop trough all channels in the pixel of the current length
            for (int i = 0; i < pixelBytes; i++)
            {
                //Take a byte from the queue of pixel values to put in the current channel
                currentPixel[i] = (byte)pixels.Dequeue();
            }

            //Loop trough all lines of pixels
            for (int y = 0; y < height; y++)
            {
                //Loop trough all pixels in this line
                for (int x = 0; x < width; x++)
                {
                    //Set the bit of the current pixel to the value of the current run
                    aBitmap.SetPixel(x, y, currentPixel);

                    //Decrease the length of the current run
                    pixelsToGo--;

                    //If the end of the run has been reached
                    if (pixelsToGo == 0 && (x * y != (height - 1) * (width - 1)))
                    {
                        //Read the new run length from the BitStream
                        pixelsToGo = runs.Dequeue() + 1;

                        //Loop trough all channels in the pixel of the current length
                        for (int i = 0; i < pixelBytes; i++)
                        {
                            //Take a byte from the queue of pixel values to put in the current channel
                            currentPixel[i] = (byte)pixels.Dequeue();
                        }
                    }
                }
            }

            //Return the image as aBitmap
            return(aBitmap);
        }
Exemple #4
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 aBitmap from raw data
            AccessibleBitmap aBitmap = new AccessibleBitmap(width, height, pixelBytes);

            aBitmap.SetRawPixelBytes(source);

            //Return the created bitmap
            return(aBitmap);
        }
Exemple #5
0
            public AccessibleBitmap GetAccessibleBitmap()
            {
                byte[] tmpBytes = new byte[width * height * pixelBytes];
                new BitArray(boolArray).CopyTo(tmpBytes, 0);

                AccessibleBitmap aBitmap = new AccessibleBitmap(width, height, pixelBytes);

                aBitmap.SetRawPixelBytes(tmpBytes);

                return(aBitmap);
            }
Exemple #6
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)
        {
            BitStreamFIFO layerBits = new BitStreamFIFO(source);

            int[] byteArray = VaryingIntArrayCompressor.Decompress(ref layerBits);

            //Create aBitmap from pixel data
            AccessibleBitmap aBitmap = new AccessibleBitmap(width, height, pixelBytes);

            aBitmap.SetRawPixelBytes(Array.ConvertAll(byteArray, Convert.ToByte));

            return(aBitmap);
        }
        //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());
        }
Exemple #8
0
        // This function is used to compress the image using the LZW algorithm
        public static byte[] Compress(AccessibleBitmap source)
        {
            // Add first 255 standard values to LZWDictionary in LZWCompressor.cs
            string[] LZWDictionary = new string[256];
            for (int i = 0; i < 256; i++)
            {
                LZWDictionary[i] = ((char)i).ToString();
            }

            List <string> dictionary     = new List <string>(LZWDictionary);            // Clone dictionary of all bytes
            Queue <byte>  bytes          = new Queue <byte>(source.GetRawPixelBytes()); // Get all bytes from the source image
            BitStreamFIFO bs             = new BitStreamFIFO();                         // Create bitstream for output
            int           maxDictSize    = (int)Math.Pow(2, maxBitCount);               // Get maximum dictionary size
            string        encodingString = ((char)bytes.Dequeue()).ToString();          // Create string to add encoding to

            while (bytes.Count > 0)
            {
                // Clear dict if full
                if (dictionary.Count >= maxDictSize)
                {
                    dictionary = new List <string>(LZWDictionary);
                }

                char b = (char)bytes.Dequeue();

                if (dictionary.Contains(encodingString + b))
                {
                    encodingString += b;
                }
                else
                {
                    bs.Write(dictionary.FindIndex(x => x.StartsWith(encodingString)), maxBitCount);
                    dictionary.Add(encodingString + b);
                    encodingString = b.ToString();
                }
            }

            // Write remaining byte to bitstream
            bs.Write(dictionary.FindIndex(x => x.StartsWith(encodingString)), maxBitCount);

            // Return the bitstream as byte array
            return(bs.ToByteArray());
        }
Exemple #9
0
        public static AccessibleBitmap Decompress(byte[] source, int width, int height, int pixelBytes)
        {
            BitStreamFIFO bs = new BitStreamFIFO(source);                               // Convert the image into a bitstream
            bool verticallyCompressed = bs.ReadBool();                                  // Store if image was vertically compressed or not
            int maxBitCount = bs.ReadByte();                                            // Get the highest bitcount value
            AccessibleBitmap bmp = new AccessibleBitmap(width, height, pixelBytes);     // Create new bitmap to write all pixels to

            // Ints to keep track of coords
            int x = 0;
            int y = 0;

            // Loop while there are still bits to read
            while (bs.Length > maxBitCount)
            {
                int counterValue = bs.ReadInt(maxBitCount);     // Get the counter value of the next pixel value
                byte[] pixel = bs.ReadByteArray(pixelBytes);    // Get the pixel value

                for (int i = 0; i < counterValue; i++)
                {
                    bmp.SetPixel(x, y, pixel);
                    if (verticallyCompressed)
                    {
                        y++;
                        if (y >= height)
                        {
                            x++;
                            y = 0;
                        }
                    }else
                    {
                        x++;
                        if (x >= width)
                        {
                            y++;
                            x = 0;
                        }
                    }
                }
            }

            // Return the bitmap
            return bmp;
        }
Exemple #10
0
 //Compress aBitmap into byte array
 public static byte[] Compress(AccessibleBitmap source)
 {
     return(VaryingIntArrayCompressor.Compress(Array.ConvertAll(source.GetRawPixelBytes(), Convert.ToInt32)).ToByteArray());
 }
Exemple #11
0
        public static byte[] CompressVertical(AccessibleBitmap source)
        {
            byte[] lastpixel = null;                                // Create variable to store the last pixel
            int colorCounter = 1;                                   // Create counter for current color
            BitStreamFIFO bs = new BitStreamFIFO();                 // Create new bitstream for all the bits
            int maxCount = 0;                                       // Create variable to store the max bitcount
            Queue<PixelArray> output = new Queue<PixelArray>();     // Create list to store all the pixelvalues in

            // Write one bit to the bitstream, so the decompressor knows to decompress vertically
            bs.Write(true);

            // Iterate through every vertical row
            for (int x = 0; x < source.width; x++)
            {
                // Iterate through every pixel in the vertical row
                for (int y = 0; y < source.height; y++)
                {
                    // Check if the variable lastpixel is empty
                    if (lastpixel == null)
                    {
                        // If lastpixel is empty, set last pixel to the first pixel
                        lastpixel = source.GetPixel(x, y);
                    }
                    else
                    {
                        // If lastpixel isn't empty, compare last pixel with new pixel
                        if (lastpixel.SequenceEqual(source.GetPixel(x, y)))
                        {
                            // Pixels matched, so increase the counter value
                            colorCounter++;
                        }
                        else
                        {
                            // If the pixels don't match, add the counter with the last pixel to the output queue
                            output.Enqueue(new PixelArray(colorCounter, lastpixel));
                            // Check if the new countervalue is higher then the last one, if so set maxBitCount to that
                            if (colorCounter > maxCount)
                                maxCount = colorCounter;

                            // Reset the colorCounter and set the last pixel to the new pixel
                            colorCounter = 1;
                            lastpixel = source.GetPixel(x, y);
                        }
                    }
                }
            }

            // Add the remaining pixel(s) to the bitstream
            output.Enqueue(new PixelArray(colorCounter, lastpixel));
            // Check if the new countervalue is higher then the last one, if so set maxBitCount to that
            if (colorCounter > maxCount)
                maxCount = colorCounter;

            // Write the maxCount to the bitstream
            bs.Write((byte)Math.Ceiling(Math.Log(maxCount, 2)));

            // Add all the pixels from the queue to the bitstream
            while (output.Count > 0)
            {
                PixelArray pixel = output.Dequeue();
                bs.Write(pixel.Count, (int)Math.Ceiling(Math.Log(maxCount, 2)));
                bs.Write(pixel.Pixel);
            }

            // Return the bitsream as a byte[]
            return bs.ToByteArray();
        }
        //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());
        }
Exemple #13
0
 //Compress aBitmap into byte array
 public static byte[] Compress(AccessibleBitmap source)
 {
     //Return raw aBitmap
     return(source.GetRawPixelBytes());
 }
Exemple #14
0
        //Decodes a byte array containing a compressed APIF image to a C# Bitmap image
        public Bitmap Decode(byte[] bytes)
        {
            //Check if the file version matches the version of the this decoder
            if (bytes[0] != version)
            {
                throw new Exception("Version not matching");
            }

            //Start timer for decoding time
            encodingStart = DateTime.Now.TimeOfDay;

            //Read the header info to the correct variables
            int pixelBytes = bytes[1];                  //The amount of color channels
            int width      = bytes[2] * 256 + bytes[3]; //The image width
            int height     = bytes[4] * 256 + bytes[5]; //The image heigth

            compressionType = bytes[6];                 //The compression type

            //Store the image data apart from the header
            byte[] image = new byte[bytes.Length - 7];
            Array.Copy(bytes, 7, image, 0, image.Length);

            //Initialize
            AccessibleBitmap outputBitmap = null;   //The final AccessibleBitmap object

            //Choose the right decoding type from the header info
            switch (compressionType)
            {
            //Uncompressed bitmap
            case 0:
                outputBitmap = UncompressedBitmapCompressor.Decompress(image, width, height, pixelBytes);
                break;

            //Individual compressed color channels merged together
            case 1:
                outputBitmap = ByteLayerVaryingCompression.Decompress(image, width, height, pixelBytes);
                break;

            //Run length encoding
            case 2:
                outputBitmap = RunLengthEncodingCompressor.Decompress(image, width, height, pixelBytes);
                break;

            //Run length encoding vertical
            case 3:
                outputBitmap = RunLengthEncodingCompressorVertical.Decompress(image, width, height, pixelBytes);
                break;

            //LZW compression
            case 4:
                outputBitmap = LZWCompressor.Decompress(image, width, height, pixelBytes);
                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");
            }

            //Stop timer
            encodingStop = DateTime.Now.TimeOfDay;
            SetStatus("Finished");

            //Calculate compression rate in bytes per pixel
            compressionRate = (double)bytes.Length / (outputBitmap.width * outputBitmap.height);

            //Return the output image as bitmap format
            return(outputBitmap.GetBitmap());
        }
Exemple #15
0
        //Encodes a C# Bitmap image to a byte array containing this image compressed as APIF image
        public byte[] Encode(Bitmap bitmap)
        {
            //Start timer for compression time
            encodingStart = DateTime.Now.TimeOfDay;

            //Creates a AccessibleBitmap class for the input bitmap: this class makes reading pixels easier and faster
            AccessibleBitmap aBitmap = new AccessibleBitmap(bitmap);

            //Compress image using all different compression techniques, where possible at the same time
            byte[][] compressionTechniques = new byte[4][];
            Parallel.For(0, compressionTechniques.Length, (i, state) =>
            {
                switch (i)
                {
                //Uncompressed (only used if no compression technique is smaller)
                case 0:
                    compressionTechniques[i] = UncompressedBitmapCompressor.Compress(aBitmap);
                    break;

                //Split colors in their channels and apply compression over them
                case 1:
                    compressionTechniques[i] = ByteLayerVaryingCompression.Compress(aBitmap);
                    break;

                //Run length compression: save the length of a sequence of pixels with the same color instead of saving them seperately
                case 2:
                    compressionTechniques[i] = RunLengthEncodingCompressor.Compress(aBitmap);
                    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] = RunLengthEncodingCompressorVertical.Compress(aBitmap);
                    break;

                    //LZW compression: save sequences of pixels as a single value, without the need of adding a dictionary\
                    // REMOVED BECAUSE VERY SLOW AND NOT PROPERLY WORKING
                    //case 4:
                    //compressionTechniques[i] = LZWCompressor.Compress(aBitmap);
                    //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;
            int smallestSize = int.MaxValue;

            //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;
                }
            }

            //Set the output byte array to the output of the smallest compression technique
            byte[] image = compressionTechniques[smallestID];
            compressionType = smallestID;

            //Build the file header containing information for the decoder
            byte[] header = new byte[7];
            header[0] = (byte)version;                  //This byte indicates the version of the compressor, to handle possible changes in the future
            header[1] = (byte)aBitmap.pixelBytes;       //This byte indicates the amount of color channels in the image
            header[2] = (byte)(aBitmap.width >> 8);     //These 2 bytes together indicate the width of the image
            header[3] = (byte)aBitmap.width;            //The reason for using 2 bytes instead of 1, is that 1 byte can store a width of 0-255, while 2 bytes can store 0-65535
            header[4] = (byte)(aBitmap.height >> 8);    //These 2 bytes together indicate the heigth of the image
            header[5] = (byte)aBitmap.height;           //The reason for using 2 bytes instead of 1, is that 1 byte can store a width of 0-255, while 2 bytes can store 0-65535
            header[6] = (byte)compressionType;          //This contains the number of the compression technique used

            //Merge the header with the image data to form the fimal file data
            byte[] fileBytes = new byte[header.Length + image.Length];
            Array.Copy(header, fileBytes, header.Length);
            Array.Copy(image, 0, fileBytes, header.Length, image.Length);

            //Stop timer
            encodingStop    = DateTime.Now.TimeOfDay;
            compressionRate = (double)fileBytes.Length / (aBitmap.width * aBitmap.height);

            //Return final file as byte array
            return(fileBytes);
        }