public async Task <Image> Convert()
        {
            ChangeDitherer();
            ChangeQuantizer();
            ChangeColorCache();
            ChangeColorModel();

            // tries to retrieve an image based on HSB quantization
            int           parallelTaskCount = activeQuantizer.AllowParallel ? GetParallelCount() : 1;
            TaskScheduler uiScheduler       = TaskScheduler.FromCurrentSynchronizationContext();
            int           colorCount        = GetColorCount();

            // disables all the controls and starts running
            sourceImage = Image.FromFile(InputFileName);

            // quantization process
            Task quantization = Task.Factory.StartNew(() =>
                                                      targetImage = ImageBuffer.QuantizeImage(sourceImage, activeQuantizer, activeDitherer, colorCount, parallelTaskCount),
                                                      TaskCreationOptions.LongRunning);

            // finishes after running
            await quantization.ContinueWith(task =>
            {
                // detects error and color count
                int originalColorCount = activeQuantizer.GetColorCount();

                // retrieves a BMP image based on our HSB-quantized one
                GetConvertedImage(targetImage, ImageFormat.Bmp, out int newBmpSize);
            }, uiScheduler);

            return(targetImage);
        }
Exemple #2
0
        //============================================================
        // <T>存储索引颜色。</T>
        //
        // @param output 输出流
        // @param quantizer 优化器
        // @param bitmap 位图对象
        //============================================================
        protected void StoreIndexedColor(IOutput output, Bitmap bitmap, int colorCount, int cx, int cy)
        {
            // 优化图形
            FPictureQuantizer pictureQuantizer = new FPictureQuantizer(_quantizerCd);
            IColorQuantizer   colorQuantizer   = pictureQuantizer.LoadQuantizerColors(bitmap, FPictureQuantizer.EQuantizedMode.Rgb);
            int colorTotal = colorQuantizer.GetColorCount();

            // 构造调色板
            Color[] palette = colorQuantizer.MakePalette(colorCount).ToArray();
            // 输出调色板
            int paletteCount = palette.Length;

            output.WriteUint8((byte)paletteCount);
            foreach (Color color in palette)
            {
                output.WriteInt32(color.ToArgb() & 0x00FFFFFF);
            }
            // 输出颜色数组
            int width  = bitmap.Width;
            int height = bitmap.Height;

            for (int h = 0; h < height; h++)
            {
                for (int w = 0; w < width; w++)
                {
                    Color color = bitmap.GetPixel(w, h);
                    int   index = colorQuantizer.FindPaletteIndex(Color.FromArgb(255, color));
                    output.WriteUint8((byte)index);
                    output.WriteUint8(color.A);
                }
            }
            _logger.Debug(this, "StoreIndexedColor", "Make indexed color. (position={0}-{1}, color_total={2}, color_count={3})",
                          cx, cy, colorTotal, paletteCount);
        }
        private Image GetQuantizedImage(Image image)
        {
            // checks whether a source image is valid
            if (image == null)
            {
                const String message = "Cannot quantize a null image.";
                throw new ArgumentNullException(message);
            }

            // locks the source image data
            Bitmap     bitmap     = (Bitmap)image;
            Rectangle  bounds     = Rectangle.FromLTRB(0, 0, bitmap.Width, bitmap.Height);
            BitmapData sourceData = bitmap.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

            // prepares time statistics variables
            TimeSpan duration = new TimeSpan(0);
            DateTime before;

            try
            {
                // initalizes the pixel read buffer
                Int32[] sourceBuffer = new Int32[image.Width];

                // sets the offset to the first pixel in the image
                Int64 sourceOffset = sourceData.Scan0.ToInt64();

                for (Int32 row = 0; row < image.Height; row++)
                {
                    // copies the whole row of pixels to the buffer
                    Marshal.Copy(new IntPtr(sourceOffset), sourceBuffer, 0, image.Width);

                    // scans all the colors in the buffer
                    foreach (Color color in sourceBuffer.Select(argb => Color.FromArgb(argb)))
                    {
                        before = DateTime.Now;
                        activeQuantizer.AddColor(color);
                        duration += DateTime.Now - before;
                    }

                    // increases a source offset by a row
                    sourceOffset += sourceData.Stride;
                }

                editTargetInfo.Text = string.Format("Quantized: {0} colors (duration {1})", 256, duration); // TODO
            }
            catch
            {
                bitmap.UnlockBits(sourceData);
                throw;
            }

            Bitmap result = new Bitmap(image.Width, image.Height, PixelFormat.Format8bppIndexed);

            // calculates the palette
            try
            {
                before = DateTime.Now;
                Int32        colorCount = GetColorCount();
                List <Color> palette    = activeQuantizer.GetPalette(colorCount);

                // sets our newly calculated palette to the target image
                ColorPalette imagePalette = result.Palette;
                duration += DateTime.Now - before;

                for (Int32 index = 0; index < palette.Count; index++)
                {
                    imagePalette.Entries[index] = palette[index];
                }

                result.Palette = imagePalette;
            }
            catch (Exception)
            {
                bitmap.UnlockBits(sourceData);
                throw;
            }

            // locks the target image data
            BitmapData targetData = result.LockBits(bounds, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

            try
            {
                // initializes read/write buffers
                Byte[]  targetBuffer = new Byte[result.Width];
                Int32[] sourceBuffer = new Int32[image.Width];

                // sets the offsets on the beginning of both source and target image
                Int64 sourceOffset = sourceData.Scan0.ToInt64();
                Int64 targetOffset = targetData.Scan0.ToInt64();

                for (Int32 row = 0; row < image.Height; row++)
                {
                    // reads the pixel row from the source image
                    Marshal.Copy(new IntPtr(sourceOffset), sourceBuffer, 0, image.Width);

                    // goes thru all the pixels, reads the color on the source image, and writes calculated palette index on the target
                    for (Int32 index = 0; index < image.Width; index++)
                    {
                        Color color = Color.FromArgb(sourceBuffer[index]);
                        before = DateTime.Now;
                        targetBuffer[index] = (Byte)activeQuantizer.GetPaletteIndex(color);
                        duration           += DateTime.Now - before;
                    }

                    // writes the pixel row to the target image
                    Marshal.Copy(targetBuffer, 0, new IntPtr(targetOffset), result.Width);

                    // increases the offsets (on both images) by a row
                    sourceOffset += sourceData.Stride;
                    targetOffset += targetData.Stride;
                }
            }
            finally
            {
                // releases the locks on both images
                bitmap.UnlockBits(sourceData);
                result.UnlockBits(targetData);
            }

            // spits some duration statistics (those actually slow the processing quite a bit, turn them off to make it quicker)
            editSourceInfo.Text = string.Format("Original: {0} colors ({1} x {2})", activeQuantizer.GetColorCount(), image.Width, image.Height);

            // returns the quantized image
            return(result);
        }
Exemple #4
0
        private void UpdateImages()
        {
            // only perform if image was already loaded
            if (!imageLoaded)
            {
                return;
            }

            // prepares quantizer
            errorCache.Clear();

            // tries to retrieve an image based on HSB quantization
            Int32         parallelTaskCount = activeQuantizer.AllowParallel ? Convert.ToInt32(listParallel.Text) : 1;
            TaskScheduler uiScheduler       = TaskScheduler.FromCurrentSynchronizationContext();
            Int32         colorCount        = GetColorCount();

            // disables all the controls and starts running
            sourceImage = Image.FromFile(dialogOpenFile.FileName);
            Text        = Resources.Running;
            SwitchControls(false);
            DateTime before = DateTime.Now;

            // quantization process
            Task quantization = Task.Factory.StartNew(() =>
                                                      targetImage = ImageBuffer.QuantizeImage(sourceImage, activeQuantizer, activeDitherer, colorCount, parallelTaskCount),
                                                      TaskCreationOptions.LongRunning);

            // finishes after running
            quantization.ContinueWith(task =>
            {
                // detects operation duration
                TimeSpan duration = DateTime.Now - before;
                TimeSpan perPixel = new TimeSpan(duration.Ticks / (sourceImage.Width * sourceImage.Height));

                // detects error and color count
                Int32 originalColorCount = activeQuantizer.GetColorCount();
                String nrmsdString       = string.Empty;

                // calculates NRMSD error, if requested
                if (checkShowError.Checked)
                {
                    Double nrmsd = ImageBuffer.CalculateImageNormalizedMeanError(sourceImage, targetImage, parallelTaskCount);
                    nrmsdString  = string.Format(" (NRMSD = {0:0.#####})", nrmsd);
                }

                // spits some duration statistics (those actually slow the processing quite a bit, turn them off to make it quicker)
                editSourceInfo.Text = string.Format("Original: {0} colors ({1} x {2})", originalColorCount, sourceImage.Width, sourceImage.Height);
                editTargetInfo.Text = string.Format("Quantized: {0} colors{1}", colorCount, nrmsdString);

                // new GIF and PNG sizes
                Int32 newGifSize, newPngSize;

                // retrieves a GIF image based on our HSB-quantized one
                GetConvertedImage(targetImage, ImageFormat.Gif, out newGifSize);

                // retrieves a PNG image based on our HSB-quantized one
                GetConvertedImage(targetImage, ImageFormat.Png, out newPngSize);

                // spits out the statistics
                Text = string.Format("Simple palette quantizer (duration 0:{0:00}.{1:0000000}, per pixel 0.{2:0000000})", duration.Seconds, duration.Ticks, perPixel.Ticks);
                editProjectedGifSize.Text = projectedGifSize.ToString();
                editProjectedPngSize.Text = sourceFileInfo.Length.ToString();
                editNewGifSize.Text       = newGifSize.ToString();
                editNewPngSize.Text       = newPngSize.ToString();
                pictureTarget.Image       = targetImage;

                // enables controls again
                SwitchControls(true);
            }, uiScheduler);
        }