ImageResizer  3.4.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Events
Classes | Public Member Functions | Protected Member Functions | Properties | List of all members
ImageResizer.Plugins.PrettyGifs.Quantizer Class Referenceabstract

Abstract Quantizer class - handles the messy, algorithm-independent details of quantization. Subclasses must implement InitialQuantizePixel, GetPallete(), and QuantizePixel. Not thread-safe! More...

Inheritance diagram for ImageResizer.Plugins.PrettyGifs.Quantizer:
Inheritance graph
[legend]

Classes

struct  Color32
 Struct that defines a 32 bpp colour More...
 

Public Member Functions

 Quantizer (bool fixedPalette)
 Construct the quantizer More...
 
virtual void Reset ()
 Resets the quantizer so it can process a new image. More...
 
Bitmap Quantize (Image src)
 Quantize an image and return the resulting output bitmap More...
 

Protected Member Functions

virtual void ValidatePropertyValues ()
 
Bitmap QuantizeFullTrust (Bitmap firstPass, Bitmap copy, Bitmap copy2, Bitmap output)
 
Bitmap QuantizeLowTrust (Bitmap firstPass, Bitmap copy, Bitmap copy2, Bitmap output)
 
virtual void AnalyzeImage (BitmapData sourceData, int width, int height)
 Execute the first pass through the pixels in the image More...
 
virtual void AnalyzeImageLowTrust (Bitmap b, int width, int height)
 
virtual void QuantizeImage (BitmapData sourceData, BitmapData intermediate, Bitmap output, int width, int height, Rectangle bounds)
 Execute a second pass through the bitmap. If dithering is enabled, sourceData will be modified. More...
 
void AdjustNeighborSource (int offsetX, int offsetY, int deltaR, int deltaG, int deltaB, int deltaA)
 Can only be called from QuantizePixel... This is how dithering is done... 5-18-09 ndj More...
 
byte ToByte (int i)
 
virtual void InitialQuantizePixel (Color32 pixel)
 Override this to process the pixel in the first pass of the algorithm More...
 
abstract byte QuantizePixel (Color32 pixel)
 Override this to process the pixel in the second pass of the algorithm More...
 
abstract ColorPalette GetPalette (ColorPalette original)
 Retrieve the palette for the quantized image More...
 

Properties

bool FixedPalette [get]
 (Readonly) If true, the algorithm can do everything in QuantizePixel, and InitialQuantizePixel will not be called. Implies ResizeForFirstPass=False and FourPass=false= More...
 
int PixelSize [get]
 The number of bytes in a ARGB structure. Should be 4 More...
 
bool FullTrust [get, set]
 If true, pointer arithmetic will be used instead of GetPixel. GetPixel is much slower. If false, OmitFinalStage will be assumed true, as only palette generation is possible in low trust. Defaults to true. More...
 
bool ResizeForFirstPass [get, set]
 If true, the first pass (InitialQuantizePixel) will be performed on a size-limited version of the original image to control performance. Ignored if FixedPalette=True More...
 
long FirstPassPixelCount [get, set]
 The approximate number of pixels to use when making a scaled copy of the image for the first pass. Only used when ResizeForFirstPass=True and FirstPassPixelThreshold is exceeded. More...
 
long FirstPassPixelThreshold [get, set]
 The maximum number of pixels the original image may contain before a scaled copy is made for the first pass. Only relevant when ResizeForFirstPass=True More...
 
bool FourPass [get, set]
 If true, image is re-paletted after quantization - forces 2 clones of the original image to be created. FixedPalette and OmitFinalStage should be false if this is used. More...
 
bool OmitFinalStage [get, set]
 If true, a 32-bit image with an 8-bit palette will be returned instead of an 8-bit image, which GDI can save using median-cut quantization. Much faster than our final quantization pass, although it can't do transparency. Assumed true if FullTrust is false. More...
 

Detailed Description

Abstract Quantizer class - handles the messy, algorithm-independent details of quantization. Subclasses must implement InitialQuantizePixel, GetPallete(), and QuantizePixel. Not thread-safe!

Definition at line 31 of file Quantizer.cs.

Constructor & Destructor Documentation

ImageResizer.Plugins.PrettyGifs.Quantizer.Quantizer ( bool  fixedPalette)
inline

Construct the quantizer

Parameters
fixedPaletteIf true, the quantization only needs to loop through the source pixels once - InitialQuantiize

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'.

Definition at line 122 of file Quantizer.cs.

123  {
124  _fixedPalette = fixedPalette;
125  _pixelSize = Marshal.SizeOf(typeof (Color32));
126  }

Member Function Documentation

void ImageResizer.Plugins.PrettyGifs.Quantizer.AdjustNeighborSource ( int  offsetX,
int  offsetY,
int  deltaR,
int  deltaG,
int  deltaB,
int  deltaA 
)
inlineprotected

Can only be called from QuantizePixel... This is how dithering is done... 5-18-09 ndj

Parameters
offsetX
offsetY
deltaR
deltaG
deltaB
deltaA

Definition at line 461 of file Quantizer.cs.

462  {
463  if (secondPassIntermediate == null) return;
464  int x = secondPassX + offsetX;
465  int y = secondPassY + offsetY;
466  if (x < 0 || x >= secondPassIntermediate.Width) return; //do nothing;
467  if (y < 0 || y >= secondPassIntermediate.Height) return; //do nothing
468  IntPtr p = (IntPtr)((long)secondPassIntermediate.Scan0 + ((long)y * (long)secondPassIntermediate.Stride) + (PixelSize * x));
469  //Read the original color
470  Color32 c = new Color32(p);
471 
472  c.Red = ToByte((int)c.Red + deltaR);
473  c.Green = ToByte((int)c.Green + deltaG);
474  c.Blue = ToByte((int)c.Blue + deltaB);
475  c.Alpha = ToByte((int)c.Alpha + deltaA);
476 
477  Marshal.StructureToPtr(c, p, true); //False to not dispose old block. Since no reference to it exists (I believe PtrToStructure from Color32 copies, not references), this should be safe
478 
479  }
int PixelSize
The number of bytes in a ARGB structure. Should be 4
Definition: Quantizer.cs:47
virtual void ImageResizer.Plugins.PrettyGifs.Quantizer.AnalyzeImage ( BitmapData  sourceData,
int  width,
int  height 
)
inlineprotectedvirtual

Execute the first pass through the pixels in the image

Parameters
sourceDataThe source data
widthThe width in pixels of the image
heightThe height in pixels of the image

Definition at line 323 of file Quantizer.cs.

324  {
325  // Define the source data pointers. The source row is a byte to
326  // keep addition of the stride value easier (as this is in bytes)
327  IntPtr pSourceRow = sourceData.Scan0;
328 
329  // Loop through each row
330  for (int row = 0; row < height; row++)
331  {
332  // Set the source pixel to the first pixel in this row
333  IntPtr pSourcePixel = pSourceRow;
334 
335  // And loop through each column
336  for (int col = 0; col < width; col++)
337  {
338  InitialQuantizePixel(new Color32(pSourcePixel));
339  pSourcePixel = (IntPtr)((long)pSourcePixel + PixelSize); //Increment afterwards
340  } // Now I have the pixel, call the FirstPassQuantize function...
341 
342  // Add the stride to the source row
343  pSourceRow = (IntPtr)((long)pSourceRow + sourceData.Stride);
344  }
345  }
virtual void InitialQuantizePixel(Color32 pixel)
Override this to process the pixel in the first pass of the algorithm
Definition: Quantizer.cs:513
int PixelSize
The number of bytes in a ARGB structure. Should be 4
Definition: Quantizer.cs:47
abstract ColorPalette ImageResizer.Plugins.PrettyGifs.Quantizer.GetPalette ( ColorPalette  original)
protectedpure virtual

Retrieve the palette for the quantized image

Parameters
originalAny old palette, this is overrwritten
Returns
The new color palette

Implemented in ImageResizer.Plugins.PrettyGifs.OctreeQuantizer.

virtual void ImageResizer.Plugins.PrettyGifs.Quantizer.InitialQuantizePixel ( Color32  pixel)
inlineprotectedvirtual

Override this to process the pixel in the first pass of the algorithm

Parameters
pixelThe pixel to quantize

This function need only be overridden if your quantize algorithm needs two passes, such as an Octree quantizer.

Reimplemented in ImageResizer.Plugins.PrettyGifs.OctreeQuantizer.

Definition at line 513 of file Quantizer.cs.

514  {
515  }
Bitmap ImageResizer.Plugins.PrettyGifs.Quantizer.Quantize ( Image  src)
inline

Quantize an image and return the resulting output bitmap

Parameters
sourceThe image to quantize
Returns
A quantized version of the image

Definition at line 151 of file Quantizer.cs.

151  {
152  //We just set up the Bitmap copies and handle their disposal - the real work happens in
153  // QuantizeFullTrust and QuantizeLowTrust
154  Bitmap firstPass = null;
155  Bitmap copy = null;
156  Bitmap copy2 = null;
157  Bitmap tempOutput = null;
158  Bitmap result = null;
159  try {
160  // First off take a 32bpp copy of 'source' if it's not a 32bpp Bitmap instance.
161  copy = src as Bitmap;
162  if (FourPass || copy == null || !src.PixelFormat.Equals(PixelFormat.Format32bppArgb)) {
163  copy = new Bitmap(src.Width, src.Height, PixelFormat.Format32bppArgb);
164 
165  // Now lock the bitmap into memory
166  using (Graphics g = Graphics.FromImage(copy)) {
167  g.PageUnit = GraphicsUnit.Pixel;
168 
169  // Draw the source image onto the copy bitmap,
170  // which will effect a widening as appropriate.
171  g.DrawImage(src, new Point(0, 0));
172 
173  }
174  }
175 
176  firstPass = copy;
177  //If we should make a resized version for the first pass, let's do it.
178  if (!FixedPalette && ResizeForFirstPass && FirstPassPixelThreshold < copy.Width * copy.Height) {
179  double factor = FirstPassPixelCount / ((double)copy.Width * (double)copy.Height);
180  firstPass = new Bitmap((int)Math.Floor((double)copy.Width * factor), (int)Math.Floor((double)copy.Height * factor), PixelFormat.Format32bppArgb);
181  using (Graphics g = Graphics.FromImage(firstPass)) {
182  //Use the low-quality settings - we want the original colors of the image, nearest neighbor is better than bicubic spline here.
183  g.PageUnit = GraphicsUnit.Pixel;
184  g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
185  g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
186  g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
187  g.DrawImage(copy, 0, 0, firstPass.Width, firstPass.Height);
188  }
189  }
190  copy2 = null;
191  if (FourPass) {
192  copy2 = new Bitmap(src.Width, src.Height, PixelFormat.Format32bppArgb);
193  using (Graphics g = Graphics.FromImage(copy2)) {
194  g.PageUnit = GraphicsUnit.Pixel;
195  g.DrawImage(src, new Point(0, 0));
196  }
197  }
198  // And make an 8-bit output image
199  tempOutput = new Bitmap(OmitFinalStage ? 2 : src.Width, OmitFinalStage ? 2 : src.Height, PixelFormat.Format8bppIndexed);
200 
201  //Full trust and low trust are implemented differently.
202  if (FullTrust) {
203  result = QuantizeFullTrust(firstPass, copy, copy2, tempOutput);
204  } else {
205  result = QuantizeLowTrust(firstPass, copy, copy2, tempOutput);
206  }
207  return result;
208  } finally {
209  if (firstPass != null && firstPass != copy && firstPass != src && firstPass != result) firstPass.Dispose();
210  if (copy != null && copy != src && copy != result) copy.Dispose();
211  if (copy2 != null && copy2 != src && copy2 != result) copy2.Dispose();
212  if (tempOutput != null && tempOutput != src && tempOutput != result) tempOutput.Dispose();
213  }
214 
215  }
bool FixedPalette
(Readonly) If true, the algorithm can do everything in QuantizePixel, and InitialQuantizePixel will n...
Definition: Quantizer.cs:38
bool FourPass
If true, image is re-paletted after quantization - forces 2 clones of the original image to be create...
Definition: Quantizer.cs:96
long FirstPassPixelThreshold
The maximum number of pixels the original image may contain before a scaled copy is made for the firs...
Definition: Quantizer.cs:85
bool OmitFinalStage
If true, a 32-bit image with an 8-bit palette will be returned instead of an 8-bit image...
Definition: Quantizer.cs:107
bool FullTrust
If true, pointer arithmetic will be used instead of GetPixel. GetPixel is much slower. If false, OmitFinalStage will be assumed true, as only palette generation is possible in low trust. Defaults to true.
Definition: Quantizer.cs:56
long FirstPassPixelCount
The approximate number of pixels to use when making a scaled copy of the image for the first pass...
Definition: Quantizer.cs:75
bool ResizeForFirstPass
If true, the first pass (InitialQuantizePixel) will be performed on a size-limited version of the ori...
Definition: Quantizer.cs:66
virtual void ImageResizer.Plugins.PrettyGifs.Quantizer.QuantizeImage ( BitmapData  sourceData,
BitmapData  intermediate,
Bitmap  output,
int  width,
int  height,
Rectangle  bounds 
)
inlineprotectedvirtual

Execute a second pass through the bitmap. If dithering is enabled, sourceData will be modified.

Parameters
sourceDataThe source bitmap, locked into memory
intermediateThe intermediate bitmap, used for 4-pass quantization. If specified, output will not actually be modified
outputThe output bitmap
widthThe width in pixels of the image
heightThe height in pixels of the image
boundsThe bounding rectangle

Definition at line 371 of file Quantizer.cs.

372  {
373  secondPassIntermediate = (intermediate != null) ? intermediate : sourceData;// Not thread safe.... But nothing here is anyways...//For dithering - 5-18-09 ndj
374  BitmapData outputData = null;
375 
376  try
377  {
378  // Lock the output bitmap into memory
379  if (intermediate == null) outputData = output.LockBits(bounds, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
380 
381  // Define the source data pointers. The source row is a byte to
382  // keep addition of the stride value easier (as this is in bytes)
383  IntPtr pSourceRow = sourceData.Scan0;
384  IntPtr pSourcePixel = pSourceRow;
385  IntPtr pPreviousPixel = pSourcePixel;
386 
387  // Now define the destination data pointers
388  IntPtr pDestinationRow = IntPtr.Zero;
389  if (intermediate == null) pDestinationRow = outputData.Scan0;
390  IntPtr pDestinationPixel = pDestinationRow;
391 
392  // And convert the first pixel, so that I have values going into the loop
393 
394  byte pixelValue = QuantizePixel(new Color32(pSourcePixel));
395 
396  // Assign the value of the first pixel
397  if (intermediate == null) Marshal.WriteByte(pDestinationPixel, pixelValue);
398 
399  // Loop through each row
400  for (int row = 0; row < height; row++)
401  {
402  secondPassY = row; //For dithering - 5-18-09 ndj
403  // Set the source pixel to the first pixel in this row
404  pSourcePixel = pSourceRow;
405 
406  // And set the destination pixel pointer to the first pixel in the row
407  if (intermediate == null) pDestinationPixel = pDestinationRow;
408 
409  // Loop through each pixel on this scan line
410  for (int col = 0; col < width; col++)
411  {
412  secondPassX = col; //For dithering - 5-18-09 ndj
413  // Check if this is the same as the last pixel. If so use that value
414  // rather than calculating it again. This is an inexpensive optimisation.
415  // Nathanael: 2-11-09 changed from ReadByte to ReadInt32 on both.
416  // Otherwise this comparison may return true if only the blue component is the
417  // same in 2 subsequent pixels.
418  if (Marshal.ReadInt32(pPreviousPixel) != Marshal.ReadInt32(pSourcePixel) || (intermediate != null))
419  {
420  // Quantize the pixel
421  pixelValue = QuantizePixel(new Color32(pSourcePixel));
422 
423  // And setup the previous pointer
424  pPreviousPixel = pSourcePixel;
425  }
426 
427  // And set the pixel in the output
428  if (intermediate == null) Marshal.WriteByte(pDestinationPixel, pixelValue);
429 
430  pSourcePixel = (IntPtr)((long)pSourcePixel + PixelSize);
431  if (intermediate == null) pDestinationPixel = (IntPtr)((long)pDestinationPixel + 1);
432 
433  }
434 
435  // Add the stride to the source row
436  pSourceRow = (IntPtr)((long)pSourceRow + sourceData.Stride);
437 
438  // And to the destination row
439  if (intermediate == null) pDestinationRow = (IntPtr)((long)pDestinationRow + outputData.Stride);
440  }
441  }
442  finally
443  {
444  // Ensure that I unlock the output bits
445  if (intermediate == null) output.UnlockBits(outputData);
446  secondPassIntermediate = null;
447  }
448  }
abstract byte QuantizePixel(Color32 pixel)
Override this to process the pixel in the second pass of the algorithm
int PixelSize
The number of bytes in a ARGB structure. Should be 4
Definition: Quantizer.cs:47
abstract byte ImageResizer.Plugins.PrettyGifs.Quantizer.QuantizePixel ( Color32  pixel)
protectedpure virtual

Override this to process the pixel in the second pass of the algorithm

Parameters
pixelThe pixel to quantize
Returns
The quantized value

Implemented in ImageResizer.Plugins.PrettyGifs.OctreeQuantizer.

virtual void ImageResizer.Plugins.PrettyGifs.Quantizer.Reset ( )
inlinevirtual

Resets the quantizer so it can process a new image.

Reimplemented in ImageResizer.Plugins.PrettyGifs.OctreeQuantizer.

Definition at line 131 of file Quantizer.cs.

132  {
133  this.secondPassIntermediate = null;
134  this.secondPassX = 0;
135  this.secondPassY = 0;
136 
137  }

Property Documentation

long ImageResizer.Plugins.PrettyGifs.Quantizer.FirstPassPixelCount
getset

The approximate number of pixels to use when making a scaled copy of the image for the first pass. Only used when ResizeForFirstPass=True and FirstPassPixelThreshold is exceeded.

Definition at line 75 of file Quantizer.cs.

Referenced by ImageResizer.Plugins.PrettyGifs.PrettyGifs.SaveIndexed().

long ImageResizer.Plugins.PrettyGifs.Quantizer.FirstPassPixelThreshold
getset

The maximum number of pixels the original image may contain before a scaled copy is made for the first pass. Only relevant when ResizeForFirstPass=True

Definition at line 85 of file Quantizer.cs.

Referenced by ImageResizer.Plugins.PrettyGifs.PrettyGifs.SaveIndexed().

bool ImageResizer.Plugins.PrettyGifs.Quantizer.FixedPalette
get

(Readonly) If true, the algorithm can do everything in QuantizePixel, and InitialQuantizePixel will not be called. Implies ResizeForFirstPass=False and FourPass=false=

Definition at line 38 of file Quantizer.cs.

bool ImageResizer.Plugins.PrettyGifs.Quantizer.FourPass
getset

If true, image is re-paletted after quantization - forces 2 clones of the original image to be created. FixedPalette and OmitFinalStage should be false if this is used.

Definition at line 96 of file Quantizer.cs.

bool ImageResizer.Plugins.PrettyGifs.Quantizer.FullTrust
getset

If true, pointer arithmetic will be used instead of GetPixel. GetPixel is much slower. If false, OmitFinalStage will be assumed true, as only palette generation is possible in low trust. Defaults to true.

Definition at line 56 of file Quantizer.cs.

bool ImageResizer.Plugins.PrettyGifs.Quantizer.OmitFinalStage
getset

If true, a 32-bit image with an 8-bit palette will be returned instead of an 8-bit image, which GDI can save using median-cut quantization. Much faster than our final quantization pass, although it can't do transparency. Assumed true if FullTrust is false.

Definition at line 107 of file Quantizer.cs.

int ImageResizer.Plugins.PrettyGifs.Quantizer.PixelSize
get

The number of bytes in a ARGB structure. Should be 4

Definition at line 47 of file Quantizer.cs.

bool ImageResizer.Plugins.PrettyGifs.Quantizer.ResizeForFirstPass
getset

If true, the first pass (InitialQuantizePixel) will be performed on a size-limited version of the original image to control performance. Ignored if FixedPalette=True

Definition at line 66 of file Quantizer.cs.


The documentation for this class was generated from the following file: