diff --git a/Greenshot/Forms/QualityDialog.Designer.cs b/Greenshot/Forms/QualityDialog.Designer.cs
index 0053918df..3455c102d 100644
--- a/Greenshot/Forms/QualityDialog.Designer.cs
+++ b/Greenshot/Forms/QualityDialog.Designer.cs
@@ -46,7 +46,6 @@ namespace Greenshot {
///
private void InitializeComponent()
{
- System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(QualityDialog));
this.label_choosejpegquality = new System.Windows.Forms.Label();
this.textBoxJpegQuality = new System.Windows.Forms.TextBox();
this.trackBarJpegQuality = new System.Windows.Forms.TrackBar();
@@ -128,7 +127,7 @@ namespace Greenshot {
this.Controls.Add(this.label_choosejpegquality);
this.Controls.Add(this.textBoxJpegQuality);
this.Controls.Add(this.trackBarJpegQuality);
- this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.Icon = GreenshotPlugin.Core.GreenshotResources.getGreenshotIcon();
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "JpegQualityDialog";
diff --git a/Greenshot/Greenshot.csproj b/Greenshot/Greenshot.csproj
index 6b5cfe9d9..1e2774123 100644
--- a/Greenshot/Greenshot.csproj
+++ b/Greenshot/Greenshot.csproj
@@ -180,7 +180,6 @@
-
diff --git a/Greenshot/Helpers/ImageOutput.cs b/Greenshot/Helpers/ImageOutput.cs
index 8843de906..09405265d 100644
--- a/Greenshot/Helpers/ImageOutput.cs
+++ b/Greenshot/Helpers/ImageOutput.cs
@@ -101,11 +101,13 @@ namespace Greenshot.Helpers {
}
// If Quantizing is enable, overwrite the image to save with a 256 - color version
- if (reduceColors) {
+ IColorQuantizer quantizer = ImageHelper.PrepareQuantize((Bitmap)imageToSave);
+ int colorCount = quantizer.GetColorCount();
+ LOG.InfoFormat("Image with format {0} has {1} colors", imageToSave.PixelFormat, colorCount);
+ if (reduceColors || colorCount < 256) {
try {
LOG.Debug("Reducing colors on bitmap.");
- Quantizer quantizer = new OctreeQuantizer(255,8);
- imageToSave = quantizer.Quantize(imageToSave);
+ imageToSave = ImageHelper.Quantize((Bitmap)imageToSave, quantizer);
// Make sure the "new" image is disposed
disposeImage = true;
} catch(Exception e) {
@@ -202,7 +204,7 @@ namespace Greenshot.Helpers {
isJPG = "JPG".Equals(extension.ToUpper()) || "JPEG".Equals(extension.ToUpper());
}
- if(isJPG && conf.OutputFilePromptQuality) {
+ if(conf.OutputFilePromptQuality) {
QualityDialog qualityDialog = new QualityDialog(isJPG);
qualityDialog.ShowDialog();
quality = qualityDialog.Quality;
diff --git a/Greenshot/Helpers/QuantizerHelper.cs b/Greenshot/Helpers/QuantizerHelper.cs
deleted file mode 100644
index 690c29969..000000000
--- a/Greenshot/Helpers/QuantizerHelper.cs
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: http://getgreenshot.org/
- * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-using System;
-using System.Collections;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.Runtime.InteropServices;
-
-namespace Greenshot.Helpers {
- ///
- /// Quantizer is a method to reduce the colors in a bitmap.
- /// Currently there is only 1 implementation: OctreeQuantizer
- ///
- public unsafe abstract class Quantizer {
- ///
- /// Construct the quantizer
- ///
- /// If true, the quantization only needs to loop through the source pixels once
- ///
- /// If you construct this class with a true value for singlePass, then the code will, when quantizing your image,
- /// only call the 'QuantizeImage' function. If two passes are required, the code will call 'InitialQuantizeImage'
- /// and then 'QuantizeImage'.
- ///
- public Quantizer (bool singlePass) {
- _singlePass = singlePass ;
- }
-
- ///
- /// Quantize an image and return the resulting output bitmap
- ///
- /// The image to quantize
- /// A quantized version of the image
- public Bitmap Quantize(Image source) {
- // Get the size of the source image
- int height = source.Height ;
- int width = source.Width ;
-
- // And construct a rectangle from these dimensions
- Rectangle bounds = new Rectangle(0, 0, width, height) ;
-
- // First off take a 32bpp copy of the image
- Bitmap copy = new Bitmap ( width , height , PixelFormat.Format32bppArgb ) ;
-
- // And construct an 8bpp version
- Bitmap output = new Bitmap ( width , height , PixelFormat.Format8bppIndexed ) ;
-
- // Now lock the bitmap into memory
- using (Graphics g = Graphics.FromImage(copy)) {
- g.PageUnit = GraphicsUnit.Pixel ;
-
- // Draw the source image onto the copy bitmap,
- // which will effect a widening as appropriate.
- g.DrawImage(source, bounds ) ;
- }
-
- // Define a pointer to the bitmap data
- BitmapData sourceData = null ;
-
- try {
- // Get the source image bits and lock into memory
- sourceData = copy.LockBits ( bounds , ImageLockMode.ReadOnly , PixelFormat.Format32bppArgb ) ;
-
- // Call the FirstPass function if not a single pass algorithm.
- // For something like an octree quantizer, this will run through
- // all image pixels, build a data structure, and create a palette.
- if ( !_singlePass )
- FirstPass ( sourceData , width , height ) ;
-
- // Then set the color palette on the output bitmap. I'm passing in the current palette
- // as there's no way to construct a new, empty palette.
- output.Palette = this.GetPalette ( output.Palette ) ;
-
- // Then call the second pass which actually does the conversion
- SecondPass ( sourceData , output , width , height , bounds ) ;
- } finally {
- // Ensure that the bits are unlocked
- copy.UnlockBits ( sourceData );
- copy.Dispose();
- }
-
- // Last but not least, return the output bitmap
- return output;
- }
-
- ///
- /// Execute the first pass through the pixels in the image
- ///
- /// The source data
- /// The width in pixels of the image
- /// The height in pixels of the image
- protected virtual void FirstPass ( BitmapData sourceData , int width , int height ) {
- // Define the source data pointers. The source row is a byte to
- // keep addition of the stride value easier (as this is in bytes)
- byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer ( ) ;
- Int32* pSourcePixel ;
-
- // Loop through each row
- for ( int row = 0 ; row < height ; row++ ) {
- // Set the source pixel to the first pixel in this row
- pSourcePixel = (Int32*) pSourceRow ;
-
- // And loop through each column
- for ( int col = 0 ; col < width ; col++ , pSourcePixel++ ) {
- // Now I have the pixel, call the FirstPassQuantize function...
- InitialQuantizePixel ( (Color32*)pSourcePixel ) ;
- }
-
- // Add the stride to the source row
- pSourceRow += sourceData.Stride ;
- }
- }
-
- ///
- /// Execute a second pass through the bitmap
- ///
- /// The source bitmap, locked into memory
- /// The output bitmap
- /// The width in pixels of the image
- /// The height in pixels of the image
- /// The bounding rectangle
- protected virtual void SecondPass ( BitmapData sourceData , Bitmap output , int width , int height , Rectangle bounds ) {
- BitmapData outputData = null ;
-
- try {
- // Lock the output bitmap into memory
- outputData = output.LockBits ( bounds , ImageLockMode.WriteOnly , PixelFormat.Format8bppIndexed ) ;
-
- // Define the source data pointers. The source row is a byte to
- // keep addition of the stride value easier (as this is in bytes)
- byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer ( ) ;
- Int32* pSourcePixel = (Int32*)pSourceRow ;
- Int32* pPreviousPixel = pSourcePixel ;
-
- // Now define the destination data pointers
- byte* pDestinationRow = (byte*) outputData.Scan0.ToPointer();
- byte* pDestinationPixel = pDestinationRow ;
-
- // And convert the first pixel, so that I have values going into the loop
- byte pixelValue = QuantizePixel ( (Color32*)pSourcePixel ) ;
-
- // Assign the value of the first pixel
- *pDestinationPixel = pixelValue ;
-
- // Loop through each row
- for ( int row = 0 ; row < height ; row++ ) {
- // Set the source pixel to the first pixel in this row
- pSourcePixel = (Int32*) pSourceRow ;
-
- // And set the destination pixel pointer to the first pixel in the row
- pDestinationPixel = pDestinationRow ;
-
- // Loop through each pixel on this scan line
- for ( int col = 0 ; col < width ; col++ , pSourcePixel++ , pDestinationPixel++ ) {
- // Check if this is the same as the last pixel. If so use that value
- // rather than calculating it again. This is an inexpensive optimisation.
- if ( *pPreviousPixel != *pSourcePixel ) {
- // Quantize the pixel
- pixelValue = QuantizePixel ( (Color32*)pSourcePixel ) ;
-
- // And setup the previous pointer
- pPreviousPixel = pSourcePixel ;
- }
-
- // And set the pixel in the output
- *pDestinationPixel = pixelValue ;
- }
-
- // Add the stride to the source row
- pSourceRow += sourceData.Stride ;
-
- // And to the destination row
- pDestinationRow += outputData.Stride ;
- }
- } finally {
- // Ensure that I unlock the output bits
- output.UnlockBits ( outputData ) ;
- }
- }
-
- ///
- /// Override this to process the pixel in the first pass of the algorithm
- ///
- /// The pixel to quantize
- ///
- /// This function need only be overridden if your quantize algorithm needs two passes,
- /// such as an Octree quantizer.
- ///
- protected virtual void InitialQuantizePixel ( Color32* pixel ) {
- }
-
- ///
- /// Override this to process the pixel in the second pass of the algorithm
- ///
- /// The pixel to quantize
- /// The quantized value
- protected abstract byte QuantizePixel ( Color32* pixel ) ;
-
- ///
- /// Retrieve the palette for the quantized image
- ///
- /// Any old palette, this is overrwritten
- /// The new color palette
- protected abstract ColorPalette GetPalette ( ColorPalette original ) ;
-
- ///
- /// Flag used to indicate whether a single pass or two passes are needed for quantization.
- ///
- private bool _singlePass ;
-
- ///
- /// Struct that defines a 32 bpp colour
- ///
- ///
- /// This struct is used to read data from a 32 bits per pixel image
- /// in memory, and is ordered in this manner as this is the way that
- /// the data is layed out in memory
- ///
- [StructLayout(LayoutKind.Explicit)]
- public struct Color32 {
- ///
- /// Holds the blue component of the colour
- ///
- [FieldOffset(0)]
- public byte Blue ;
- ///
- /// Holds the green component of the colour
- ///
- [FieldOffset(1)]
- public byte Green ;
- ///
- /// Holds the red component of the colour
- ///
- [FieldOffset(2)]
- public byte Red ;
- ///
- /// Holds the alpha component of the colour
- ///
- [FieldOffset(3)]
- public byte Alpha ;
-
- ///
- /// Permits the color32 to be treated as an int32
- ///
- [FieldOffset(0)]
- public int ARGB ;
-
- ///
- /// Return the color for this Color32 object
- ///
- public Color Color {
- get { return Color.FromArgb ( Alpha , Red , Green , Blue ) ; }
- }
- }
- }
-
- ///
- /// Quantize using an Octree
- ///
- public unsafe class OctreeQuantizer : Quantizer {
- ///
- /// Construct the octree quantizer
- ///
- ///
- /// The Octree quantizer is a two pass algorithm. The initial pass sets up the octree,
- /// the second pass quantizes a color based on the nodes in the tree
- ///
- /// The maximum number of colors to return
- /// The number of significant bits
- public OctreeQuantizer ( int maxColors , int maxColorBits ) : base ( false ) {
- if ( maxColors > 255 ) {
- throw new ArgumentOutOfRangeException ( "maxColors" , maxColors , "The number of colors should be less than 256" ) ;
- }
-
- if ( ( maxColorBits < 1 ) | ( maxColorBits > 8 ) ) {
- throw new ArgumentOutOfRangeException ( "maxColorBits" , maxColorBits , "This should be between 1 and 8" ) ;
- }
-
- // Construct the octree
- _octree = new Octree ( maxColorBits ) ;
-
- _maxColors = maxColors ;
- }
-
- ///
- /// Process the pixel in the first pass of the algorithm
- ///
- /// The pixel to quantize
- ///
- /// This function need only be overridden if your quantize algorithm needs two passes,
- /// such as an Octree quantizer.
- ///
- protected override void InitialQuantizePixel ( Color32* pixel ) {
- // Add the color to the octree
- _octree.AddColor ( pixel ) ;
- }
-
- ///
- /// Override this to process the pixel in the second pass of the algorithm
- ///
- /// The pixel to quantize
- /// The quantized value
- protected override byte QuantizePixel ( Color32* pixel ) {
- byte paletteIndex = (byte)_maxColors ; // The color at [_maxColors] is set to transparent
-
- // Get the palette index if this non-transparent
- if ( pixel->Alpha > 0 ) {
- paletteIndex = (byte)_octree.GetPaletteIndex ( pixel ) ;
- }
-
- return paletteIndex ;
- }
-
- ///
- /// Retrieve the palette for the quantized image
- ///
- /// Any old palette, this is overrwritten
- /// The new color palette
- protected override ColorPalette GetPalette ( ColorPalette original ) {
- // First off convert the octree to _maxColors colors
- ArrayList palette = _octree.Palletize ( _maxColors - 1 ) ;
-
- // Then convert the palette based on those colors
- for ( int index = 0 ; index < palette.Count ; index++ )
- original.Entries[index] = (Color)palette[index] ;
-
- // Add the transparent color
- original.Entries[_maxColors] = Color.FromArgb ( 0 , 0 , 0 , 0 ) ;
-
- return original ;
- }
-
- ///
- /// Stores the tree
- ///
- private Octree _octree ;
-
- ///
- /// Maximum allowed color depth
- ///
- private int _maxColors ;
-
- ///
- /// Class which does the actual quantization
- ///
- private class Octree {
- ///
- /// Construct the octree
- ///
- /// The maximum number of significant bits in the image
- public Octree ( int maxColorBits ) {
- _maxColorBits = maxColorBits ;
- _leafCount = 0 ;
- _reducibleNodes = new OctreeNode[9] ;
- _root = new OctreeNode ( 0 , _maxColorBits , this ) ;
- _previousColor = 0 ;
- _previousNode = null ;
- }
-
- ///
- /// Add a given color value to the octree
- ///
- ///
- public void AddColor ( Color32* pixel ) {
- // Check if this request is for the same color as the last
- if ( _previousColor == pixel->ARGB ) {
- // If so, check if I have a previous node setup. This will only ocurr if the first color in the image
- // happens to be black, with an alpha component of zero.
- if ( null == _previousNode ) {
- _previousColor = pixel->ARGB ;
- _root.AddColor ( pixel , _maxColorBits , 0 , this ) ;
- } else {
- // Just update the previous node
- _previousNode.Increment ( pixel ) ;
- }
- } else {
- _previousColor = pixel->ARGB ;
- _root.AddColor ( pixel , _maxColorBits , 0 , this ) ;
- }
- }
-
- ///
- /// Reduce the depth of the tree
- ///
- public void Reduce ( ) {
- int index ;
-
- // Find the deepest level containing at least one reducible node
- for ( index = _maxColorBits - 1 ; ( index > 0 ) && ( null == _reducibleNodes[index] ) ; index-- ) ;
-
- // Reduce the node most recently added to the list at level 'index'
- OctreeNode node = _reducibleNodes[index] ;
- _reducibleNodes[index] = node.NextReducible ;
-
- // Decrement the leaf count after reducing the node
- _leafCount -= node.Reduce ( ) ;
-
- // And just in case I've reduced the last color to be added, and the next color to
- // be added is the same, invalidate the previousNode...
- _previousNode = null ;
- }
-
- ///
- /// Get/Set the number of leaves in the tree
- ///
- public int Leaves {
- get { return _leafCount ; }
- set { _leafCount = value ; }
- }
-
- ///
- /// Return the array of reducible nodes
- ///
- protected OctreeNode[] ReducibleNodes {
- get { return _reducibleNodes ; }
- }
-
- ///
- /// Keep track of the previous node that was quantized
- ///
- /// The node last quantized
- protected void TrackPrevious ( OctreeNode node ) {
- _previousNode = node ;
- }
-
- ///
- /// Convert the nodes in the octree to a palette with a maximum of colorCount colors
- ///
- /// The maximum number of colors
- /// An arraylist with the palettized colors
- public ArrayList Palletize ( int colorCount ) {
- while ( Leaves > colorCount ) {
- Reduce();
- }
-
- // Now palettize the nodes
- ArrayList palette = new ArrayList ( Leaves ) ;
- int paletteIndex = 0 ;
- _root.ConstructPalette ( palette , ref paletteIndex ) ;
-
- // And return the palette
- return palette ;
- }
-
- ///
- /// Get the palette index for the passed color
- ///
- ///
- ///
- public int GetPaletteIndex ( Color32* pixel ) {
- return _root.GetPaletteIndex ( pixel , 0 ) ;
- }
-
- ///
- /// Mask used when getting the appropriate pixels for a given node
- ///
- private static int[] mask = new int[8] { 0x80 , 0x40 , 0x20 , 0x10 , 0x08 , 0x04 , 0x02 , 0x01 } ;
-
- ///
- /// The root of the octree
- ///
- private OctreeNode _root ;
-
- ///
- /// Number of leaves in the tree
- ///
- private int _leafCount ;
-
- ///
- /// Array of reducible nodes
- ///
- private OctreeNode[] _reducibleNodes ;
-
- ///
- /// Maximum number of significant bits in the image
- ///
- private int _maxColorBits ;
-
- ///
- /// Store the last node quantized
- ///
- private OctreeNode _previousNode ;
-
- ///
- /// Cache the previous color quantized
- ///
- private int _previousColor ;
-
- ///
- /// Class which encapsulates each node in the tree
- ///
- protected class OctreeNode {
- ///
- /// Construct the node
- ///
- /// The level in the tree = 0 - 7
- /// The number of significant color bits in the image
- /// The tree to which this node belongs
- public OctreeNode ( int level , int colorBits , Octree octree ) {
- // Construct the new node
- _leaf = ( level == colorBits ) ;
-
- _red = _green = _blue = 0 ;
- _pixelCount = 0 ;
-
- // If a leaf, increment the leaf count
- if ( _leaf ) {
- octree.Leaves++ ;
- _nextReducible = null ;
- _children = null ;
- } else {
- // Otherwise add this to the reducible nodes
- _nextReducible = octree.ReducibleNodes[level] ;
- octree.ReducibleNodes[level] = this ;
- _children = new OctreeNode[8] ;
- }
- }
-
- ///
- /// Add a color into the tree
- ///
- /// The color
- /// The number of significant color bits
- /// The level in the tree
- /// The tree to which this node belongs
- public void AddColor ( Color32* pixel , int colorBits , int level , Octree octree ) {
- // Update the color information if this is a leaf
- if ( _leaf ) {
- Increment ( pixel ) ;
- // Setup the previous node
- octree.TrackPrevious ( this ) ;
- } else {
- // Go to the next level down in the tree
- int shift = 7 - level ;
- int index = ( ( pixel->Red & mask[level] ) >> ( shift - 2 ) ) |
- ( ( pixel->Green & mask[level] ) >> ( shift - 1 ) ) |
- ( ( pixel->Blue & mask[level] ) >> ( shift ) ) ;
-
- OctreeNode child = _children[index] ;
-
- if ( null == child ) {
- // Create a new child node & store in the array
- child = new OctreeNode ( level + 1 , colorBits , octree ) ;
- _children[index] = child ;
- }
-
- // Add the color to the child node
- child.AddColor ( pixel , colorBits , level + 1 , octree ) ;
- }
-
- }
-
- ///
- /// Get/Set the next reducible node
- ///
- public OctreeNode NextReducible {
- get { return _nextReducible ; }
- set { _nextReducible = value ; }
- }
-
- ///
- /// Return the child nodes
- ///
- public OctreeNode[] Children {
- get { return _children ; }
- }
-
- ///
- /// Reduce this node by removing all of its children
- ///
- /// The number of leaves removed
- public int Reduce ( ) {
- _red = _green = _blue = 0 ;
- int children = 0 ;
-
- // Loop through all children and add their information to this node
- for ( int index = 0 ; index < 8 ; index++ ) {
- if ( null != _children[index] ) {
- _red += _children[index]._red ;
- _green += _children[index]._green ;
- _blue += _children[index]._blue ;
- _pixelCount += _children[index]._pixelCount ;
- ++children ;
- _children[index] = null ;
- }
- }
-
- // Now change this to a leaf node
- _leaf = true ;
-
- // Return the number of nodes to decrement the leaf count by
- return ( children - 1 ) ;
- }
-
- ///
- /// Traverse the tree, building up the color palette
- ///
- /// The palette
- /// The current palette index
- public void ConstructPalette ( ArrayList palette , ref int paletteIndex ) {
- if ( _leaf ) {
- // Consume the next palette index
- _paletteIndex = paletteIndex++ ;
-
- // And set the color of the palette entry
- palette.Add ( Color.FromArgb ( _red / _pixelCount , _green / _pixelCount , _blue / _pixelCount ) ) ;
- } else {
- // Loop through children looking for leaves
- for ( int index = 0 ; index < 8 ; index++ ) {
- if ( null != _children[index] ) {
- _children[index].ConstructPalette ( palette , ref paletteIndex ) ;
- }
- }
- }
- }
-
- ///
- /// Return the palette index for the passed color
- ///
- public int GetPaletteIndex ( Color32* pixel , int level ) {
- int paletteIndex = _paletteIndex ;
-
- if ( !_leaf ) {
- int shift = 7 - level ;
- int index = ( ( pixel->Red & mask[level] ) >> ( shift - 2 ) ) |
- ( ( pixel->Green & mask[level] ) >> ( shift - 1 ) ) |
- ( ( pixel->Blue & mask[level] ) >> ( shift ) ) ;
-
- if ( null != _children[index] ) {
- paletteIndex = _children[index].GetPaletteIndex ( pixel , level + 1 ) ;
- } else {
- throw new Exception ( "Didn't expect this!" ) ;
- }
- }
-
- return paletteIndex ;
- }
-
- ///
- /// Increment the pixel count and add to the color information
- ///
- public void Increment ( Color32* pixel ) {
- _pixelCount++ ;
- _red += pixel->Red ;
- _green += pixel->Green ;
- _blue += pixel->Blue ;
- }
-
- ///
- /// Flag indicating that this is a leaf node
- ///
- private bool _leaf ;
-
- ///
- /// Number of pixels in this node
- ///
- private int _pixelCount ;
-
- ///
- /// Red component
- ///
- private int _red ;
-
- ///
- /// Green Component
- ///
- private int _green ;
-
- ///
- /// Blue component
- ///
- private int _blue ;
-
- ///
- /// Pointers to any child nodes
- ///
- private OctreeNode[] _children ;
-
- ///
- /// Pointer to next reducible node
- ///
- private OctreeNode _nextReducible ;
-
- ///
- /// The index of this node in the palette
- ///
- private int _paletteIndex ;
- }
- }
- }
-}
diff --git a/GreenshotPlugin/Core/BitmapBuffer.cs b/GreenshotPlugin/Core/BitmapBuffer.cs
index f1943162a..e12600cd2 100644
--- a/GreenshotPlugin/Core/BitmapBuffer.cs
+++ b/GreenshotPlugin/Core/BitmapBuffer.cs
@@ -136,7 +136,7 @@ namespace GreenshotPlugin.Core {
// Set "this" rect to location 0,0
// as the Cloned Bitmap is only the part we want to work with
this.rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
- } else if (!ImageHelper.SupportsPixelFormat(sourceBmp)) {
+ } else if (!ImageHelper.SupportsPixelFormat(sourceBmp) && PixelFormat.Format8bppIndexed != sourceBmp.PixelFormat) {
throw new ArgumentException("Unsupported pixel format: " + sourceBmp.PixelFormat + " set clone to true!");
} else {
this.bitmap = sourceBmp;
@@ -268,11 +268,36 @@ namespace GreenshotPlugin.Core {
Lock();
}
}
-
- /**
- * Retrieve the color at location x,y
- * Before the first time this is called the Lock() should be called once!
- */
+
+ ///
+ /// Retrieve the color index, for 8BPP, at location x,y
+ ///
+ /// X coordinate
+ /// Y Coordinate
+ /// index
+ public byte GetColorIndexAt(int x, int y) {
+ int offset = x*bytesPerPixel+y*stride;
+ return pointer[offset];
+ }
+
+ ///
+ /// Set the color index, for 8BPP, at location x,y
+ ///
+ /// X coordinate
+ /// Y Coordinate
+ /// Color index to set
+ public void SetColorIndexAt(int x, int y, byte color) {
+ int offset = x * bytesPerPixel + y * stride;
+ pointer[offset] = color;
+ }
+
+ ///
+ /// Retrieve the color at location x,y
+ /// Before the first time this is called the Lock() should be called once!
+ ///
+ /// X coordinate
+ /// Y Coordinate
+ /// Color
public Color GetColorAt(int x, int y) {
if(x>=0 && y>=0 && x
+ /// Retrieve the color, without alpha, at location x,y
+ /// Before the first time this is called the Lock() should be called once!
+ ///
+ /// X coordinate
+ /// Y Coordinate
+ /// Color
public Color GetColorAtWithoutAlpha(int x, int y) {
if(x>=0 && y>=0 && x
+ /// Rotate the bitmap
+ ///
+ ///
+ ///
+ ///
public static Bitmap RotateFlip(Bitmap sourceBitmap, RotateFlipType rotateFlipType) {
Bitmap returnBitmap = Clone(sourceBitmap);
returnBitmap.RotateFlip(rotateFlipType);
return returnBitmap;
}
+
+ ///
+ /// Get a quantizer, so we can check if it pays off to quantize
+ ///
+ ///
+ /// IColorQuantizer
+ public static IColorQuantizer PrepareQuantize(Bitmap sourceBitmap) {
+ IColorQuantizer quantizer = new WuColorQuantizer();
+ quantizer.Prepare(sourceBitmap);
+ using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, false)) {
+ bbbSrc.Lock();
+ for (int y = 0; y < bbbSrc.Height; y++) {
+ for (int x = 0; x < bbbSrc.Width; x++) {
+ quantizer.AddColor(bbbSrc.GetColorAt(x, y));
+ }
+ }
+ }
+ return quantizer;
+ }
+
+ public static Bitmap Quantize(Bitmap sourceBitmap, IColorQuantizer quantizer) {
+ Bitmap result = new Bitmap(sourceBitmap.Width, sourceBitmap.Height, PixelFormat.Format8bppIndexed);
+ List palette = quantizer.GetPalette(255);
+ ColorPalette imagePalette = result.Palette;
+ // copies all color entries
+ for (Int32 index = 0; index < palette.Count; index++) {
+ imagePalette.Entries[index] = palette[index];
+ }
+ result.Palette = imagePalette;
+
+ using (BitmapBuffer bbbDest = new BitmapBuffer(result, false)) {
+ bbbDest.Lock();
+ using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, false)) {
+ bbbSrc.Lock();
+ for (int y = 0; y < bbbSrc.Height; y++) {
+ for (int x = 0; x < bbbSrc.Width; x++) {
+ Color originalColor = bbbSrc.GetColorAt(x, y);
+ Int32 paletteIndex = quantizer.GetPaletteIndex(originalColor);
+ bbbDest.SetColorIndexAt(x,y, (byte)paletteIndex);
+ }
+ }
+ }
+ }
+ return result;
+ }
}
}
diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj
index 3b64e31a1..69362033b 100644
--- a/GreenshotPlugin/GreenshotPlugin.csproj
+++ b/GreenshotPlugin/GreenshotPlugin.csproj
@@ -199,6 +199,7 @@
+