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