예제 #1
0
        /// The palette (color-indexing) transform replaces pixels with indices into
        /// a palette that is stored before the image data. If the palette is
        /// sufficiently small, multiple indices are packed into a single pixel.
        internal static Image PaletteTransform(BitWriter b, Image image, Palette palette)
        {
            b.WriteBits(1, 1);
            b.WriteBits(3, 2);
            WritePalette(b, palette);

            int packSize =
                palette.Count <= 2 ? 8 :
                palette.Count <= 4 ? 4 :
                palette.Count <= 16 ? 2 : 1;

            int packedWidth = (image.Width + packSize - 1) / packSize;
            var palettized  = new Image(packedWidth, image.Height);

            for (int y = 0; y < image.Height; ++y)
            {
                for (int i = 0; i < packedWidth; ++i)
                {
                    int pack = 0;
                    for (int j = 0; j < packSize; ++j)
                    {
                        int x = i * packSize + j;
                        if (x >= image.Width)
                        {
                            break;
                        }
                        int colorIndex = palette.Indices[image[x, y]];
                        pack |= colorIndex << (j * (8 / packSize));
                    }
                    palettized[i, y] = new Argb(255, 0, (byte)pack, 0);
                }
            }

            return(palettized);
        }
예제 #2
0
파일: Format.cs 프로젝트: honzasp/vp8l
 static void WriteHeader(BitWriter b, int width, int height, bool hasAlpha)
 {
     b.WriteBits(0x2f, 8); // signature
     b.WriteBits(width - 1, 14);
     b.WriteBits(height - 1, 14);
     b.WriteBits(hasAlpha ? 1 : 0, 1);
     b.WriteBits(0, 3); // version 0
 }
예제 #3
0
 /// The subtract-green transform just subtracts the value of the green
 /// channel from the red and blue channels, which usually decreases entropy
 /// in those channels.
 internal static Image SubtractGreenTransform(BitWriter b, Image image)
 {
     b.WriteBits(1, 1);
     b.WriteBits(2, 2);
     for (int i = 0; i < image.Pixels.Length; ++i)
     {
         var argb = image.Pixels[i];
         argb.R          = (byte)(argb.R - argb.G);
         argb.B          = (byte)(argb.B - argb.G);
         image.Pixels[i] = argb;
     }
     return(image);
 }
예제 #4
0
        /// The prediction transform predicts the values of pixels using their
        /// already decoded neighbors, storing only the difference between the
        /// predicted and actual value. There are 14 prediction modes and which mode
        /// is used is determined from an encoded subsample image.
        internal static Image PredictTransform(BitWriter b, Image image)
        {
            b.WriteBits(1, 1);
            b.WriteBits(0, 2);

            int tileBits      = 4;
            int tileSize      = 0;
            int blockedWidth  = 0;
            int blockedHeight = 0;

            while (tileBits < 2 + 8)
            {
                tileSize      = 1 << tileBits;
                blockedWidth  = (image.Width + tileSize - 1) / tileSize;
                blockedHeight = (image.Height + tileSize - 1) / tileSize;
                if (blockedWidth * blockedHeight < 2000)
                {
                    break;
                }
                ++tileBits;
            }

            b.WriteBits(tileBits - 2, 3);
            var blocks      = new Image(blockedWidth, blockedHeight);
            var residuals   = new Image(image.Width, image.Height);
            var accumHistos = Enumerable.Range(0, 4).Select(_ => new Histogram(256)).ToList();

            for (int y = 0; y < blockedHeight; ++y)
            {
                for (int x = 0; x < blockedWidth; ++x)
                {
                    int    bestPrediction = 0;
                    double bestEntropy    = PredictEntropy(image, tileBits, x, y, 0, accumHistos);
                    for (int i = 1; i < PREDICTIONS.Count; ++i)
                    {
                        double entropy = PredictEntropy(image, tileBits, x, y, i, accumHistos);
                        if (entropy < bestEntropy)
                        {
                            bestPrediction = i;
                            bestEntropy    = entropy;
                        }
                    }

                    blocks[x, y] = new Argb(255, 0, (byte)bestPrediction, 0);
                    PredictBlock(image, residuals, tileBits, x, y, bestPrediction, accumHistos);
                }
            }

            ImageData.WriteImageData(b, blocks, false);
            return(residuals);
        }
예제 #5
0
        /// If there are only at most two symbols in the code, it can be encoded
        /// efficiently.
        static void WriteSimpleCodeLengths(BitWriter b, List <Huffman.Code> codes)
        {
            b.WriteBits(1, 1);
            if (codes.Count == 0)
            {
                b.WriteBits(0, 3);
                return;
            }

            b.WriteBits(codes.Count - 1, 1);
            if (codes[0].Symbol <= 1)
            {
                b.WriteBits(0, 1);
                b.WriteBits(codes[0].Symbol, 1);
            }
            else
            {
                b.WriteBits(1, 1);
                b.WriteBits(codes[0].Symbol, 8);
            }
            if (codes.Count > 1)
            {
                b.WriteBits(codes[1].Symbol, 8);
            }
        }
예제 #6
0
        /// If the size of the code is larger than two, we must transmit the length
        /// of every symbol in the code. To save space, the lengths are themselves
        /// Huffman-coded with a length code, so the lengths of the length code must
        /// be stored first.
        static void WriteNormalCodeLengths(BitWriter b, List <Huffman.Code> codes)
        {
            var encodedLengths = EncodeCodeLengths(codes);
            var lengthHisto    = new Histogram(19);

            for (int i = 0; i < encodedLengths.Count; ++i)
            {
                int sym = encodedLengths[i];
                lengthHisto.Hit(sym);
                if (sym >= 16)
                {
                    i += 1;
                }
            }
            var lengthCodes = Huffman.BuildCodes(lengthHisto, 7);

            int lengthCodeCount = 0;

            for (int i = 0; i < 19; ++i)
            {
                if (lengthHisto[CODE_LENGTH_ORDER[i]] > 0)
                {
                    lengthCodeCount = i + 1;
                }
            }
            if (lengthCodeCount < 4)
            {
                lengthCodeCount = 4;
            }

            b.WriteBits(0, 1);
            b.WriteBits(lengthCodeCount - 4, 4);
            for (int i = 0; i < lengthCodeCount; ++i)
            {
                b.WriteBits(lengthCodes[CODE_LENGTH_ORDER[i]].Length, 3);
            }

            b.WriteBits(0, 1);
            for (int i = 0; i < encodedLengths.Count; ++i)
            {
                int sym = encodedLengths[i];
                b.WriteCode(lengthCodes[sym]);
                if (sym == 16)
                {
                    b.WriteBits(encodedLengths[++i], 2);
                }
                else if (sym == 17)
                {
                    b.WriteBits(encodedLengths[++i], 3);
                }
                else if (sym == 18)
                {
                    b.WriteBits(encodedLengths[++i], 7);
                }
            }
        }
예제 #7
0
        /// The palette is encoded as an image with height 1.
        static void WritePalette(BitWriter b, Palette palette)
        {
            var image = new Image(palette.Count, 1);

            for (int i = 0; i < palette.Count; ++i)
            {
                image.Pixels[i] = i == 0 ? palette.Colors[0]
          : palette.Colors[i] - palette.Colors[i - 1];
            }

            b.WriteBits(palette.Count - 1, 8);
            ImageData.WriteImageData(b, image, false);
        }
예제 #8
0
파일: Format.cs 프로젝트: honzasp/vp8l
        /// Encodes the image as a raw VP8L bitstream.
        static void WriteImageBitstream(BitWriter b, Image image)
        {
            var analysis = Analysis.AnalyzeImage(image);

            WriteHeader(b, image.Width, image.Height, analysis.HasAlpha);

            if (analysis.PaletteOrNull != null)
            {
                image = Transform.PaletteTransform(b, image, analysis.PaletteOrNull);
            }
            if (analysis.UseSubtractGreen)
            {
                image = Transform.SubtractGreenTransform(b, image);
            }
            if (analysis.UsePredict)
            {
                image = Transform.PredictTransform(b, image);
            }
            b.WriteBits(0, 1);

            ImageData.WriteImageData(b, image, true, analysis.ColorCacheBits);
        }
예제 #9
0
파일: ImageData.cs 프로젝트: honzasp/vp8l
        /// Encodes the image into entropy-coded bitstream. The isRecursive flag
        /// must be true iff the data represents the main ARGB image.
        internal static void WriteImageData(BitWriter b, Image image,
                                            bool isRecursive, int colorCacheBits = 0)
        {
            if (colorCacheBits > 0)
            {
                if (colorCacheBits > 11)
                {
                    throw new ArgumentException("Too many color cache bits");
                }
                b.WriteBits(1, 1);
                b.WriteBits(colorCacheBits, 4);
            }
            else
            {
                b.WriteBits(0, 1);
            }

            if (isRecursive)
            {
                b.WriteBits(0, 1); // no meta-Huffman image
            }

            var encoded = EncodeImageData(image, colorCacheBits);
            var histos  = new List <Histogram> {
                new Histogram(256 + 24 + (colorCacheBits > 0 ? (1 << colorCacheBits) : 0)),
                new Histogram(256),
                new Histogram(256),
                new Histogram(256),
                new Histogram(40),
            };

            for (int i = 0; i < encoded.Count; ++i)
            {
                histos[0].Hit(encoded[i]);
                if (encoded[i] < 256)
                {
                    histos[1].Hit(encoded[i + 1]);
                    histos[2].Hit(encoded[i + 2]);
                    histos[3].Hit(encoded[i + 3]);
                    i += 3;
                }
                else if (encoded[i] < 256 + 24)
                {
                    histos[4].Hit(encoded[i + 2]);
                    i += 3;
                }
            }

            var codess = new List <List <Huffman.Code> >();

            for (int i = 0; i < 5; ++i)
            {
                var codes = Huffman.BuildCodes(histos[i], 16);
                CodeLengths.WriteCodeLengths(b, codes);
                codess.Add(codes);
            }

            for (int i = 0; i < encoded.Count; ++i)
            {
                b.WriteCode(codess[0][encoded[i]]);
                if (encoded[i] < 256)
                {
                    b.WriteCode(codess[1][encoded[i + 1]]);
                    b.WriteCode(codess[2][encoded[i + 2]]);
                    b.WriteCode(codess[3][encoded[i + 3]]);
                    i += 3;
                }
                else if (encoded[i] < 256 + 24)
                {
                    b.WriteBits(encoded[i + 1], ExtraBitsCount(encoded[i] - 256));
                    b.WriteCode(codess[4][encoded[i + 2]]);
                    b.WriteBits(encoded[i + 3], ExtraBitsCount(encoded[i + 2]));
                    i += 3;
                }
            }
        }