cleanup Quantizer.cs
This commit is contained in:
parent
64ea9afee5
commit
0082de7c0a
|
@ -14,11 +14,12 @@
|
||||||
|
|
||||||
// Based on: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/colorquant.asp
|
// Based on: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/colorquant.asp
|
||||||
|
|
||||||
//Bizhawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize
|
//BizHawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
|
using BizHawk.Common.NumberExtensions;
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
|
@ -27,35 +28,9 @@ namespace BizHawk.Client.EmuHawk
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flag used to indicate whether a single pass or two passes are needed for quantization.
|
/// Flag used to indicate whether a single pass or two passes are needed for quantization.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool _singlePass;
|
private readonly bool _singlePass;
|
||||||
|
|
||||||
protected bool highquality;
|
protected int DitherLevel;
|
||||||
public bool HighQuality
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return highquality;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
highquality = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int ditherLevel;
|
|
||||||
public int DitherLevel
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ditherLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ditherLevel = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Construct the quantizer
|
/// Construct the quantizer
|
||||||
|
@ -66,7 +41,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
/// only call the 'QuantizeImage' function. If two passes are required, the code will call 'InitialQuantizeImage'
|
/// only call the 'QuantizeImage' function. If two passes are required, the code will call 'InitialQuantizeImage'
|
||||||
/// and then 'QuantizeImage'.
|
/// and then 'QuantizeImage'.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public Quantizer(bool singlePass)
|
protected Quantizer(bool singlePass)
|
||||||
{
|
{
|
||||||
_singlePass = singlePass;
|
_singlePass = singlePass;
|
||||||
}
|
}
|
||||||
|
@ -83,32 +58,30 @@ namespace BizHawk.Client.EmuHawk
|
||||||
int width = source.Width;
|
int width = source.Width;
|
||||||
|
|
||||||
// And construct a rectangle from these dimensions
|
// And construct a rectangle from these dimensions
|
||||||
Rectangle bounds = new Rectangle(0, 0, width, height);
|
var bounds = new Rectangle(0, 0, width, height);
|
||||||
|
|
||||||
// First off take a 32bpp copy of the image
|
// First off take a 32bpp copy of the image
|
||||||
Bitmap copy;
|
Bitmap copy;
|
||||||
|
|
||||||
if (source is Bitmap && source.PixelFormat == PixelFormat.Format32bppArgb)
|
if (source is Bitmap bitmap && bitmap.PixelFormat == PixelFormat.Format32bppArgb)
|
||||||
{
|
{
|
||||||
copy = (Bitmap)source;
|
copy = bitmap;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
copy = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
copy = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
||||||
|
|
||||||
// Now lock the bitmap into memory
|
// Now lock the bitmap into memory
|
||||||
using (Graphics g = Graphics.FromImage(copy))
|
using Graphics g = Graphics.FromImage(copy);
|
||||||
{
|
g.PageUnit = GraphicsUnit.Pixel;
|
||||||
g.PageUnit = GraphicsUnit.Pixel;
|
|
||||||
|
|
||||||
// Draw the source image onto the copy bitmap,
|
// Draw the source image onto the copy bitmap,
|
||||||
// which will effect a widening as appropriate.
|
// which will effect a widening as appropriate.
|
||||||
g.DrawImage(source, 0, 0, bounds.Width, bounds.Height);
|
g.DrawImage(source, 0, 0, bounds.Width, bounds.Height);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// And construct an 8bpp version
|
// And construct an 8bpp version
|
||||||
Bitmap output = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
|
var output = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
|
||||||
|
|
||||||
// Define a pointer to the bitmap data
|
// Define a pointer to the bitmap data
|
||||||
BitmapData sourceData = null;
|
BitmapData sourceData = null;
|
||||||
|
@ -128,7 +101,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
// Then set the color palette on the output bitmap. I'm passing in the current palette
|
// 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.
|
// as there's no way to construct a new, empty palette.
|
||||||
output.Palette = this.GetPalette(output.Palette);
|
output.Palette = GetPalette(output.Palette);
|
||||||
|
|
||||||
// Then call the second pass which actually does the conversion
|
// Then call the second pass which actually does the conversion
|
||||||
SecondPass(sourceData, output, width, height, bounds);
|
SecondPass(sourceData, output, width, height, bounds);
|
||||||
|
@ -160,13 +133,12 @@ namespace BizHawk.Client.EmuHawk
|
||||||
// Define the source data pointers. The source row is a byte to
|
// Define the source data pointers. The source row is a byte to
|
||||||
// keep addition of the stride value easier (as this is in bytes)
|
// keep addition of the stride value easier (as this is in bytes)
|
||||||
byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer();
|
byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer();
|
||||||
int* pSourcePixel;
|
|
||||||
|
|
||||||
// Loop through each row
|
// Loop through each row
|
||||||
for (int row = 0; row < height; row++)
|
for (int row = 0; row < height; row++)
|
||||||
{
|
{
|
||||||
// Set the source pixel to the first pixel in this row
|
// Set the source pixel to the first pixel in this row
|
||||||
pSourcePixel = (Int32*)pSourceRow;
|
var pSourcePixel = (int*)pSourceRow;
|
||||||
|
|
||||||
// And loop through each column
|
// And loop through each column
|
||||||
for (int col = 0; col < width; col++, pSourcePixel++)
|
for (int col = 0; col < width; col++, pSourcePixel++)
|
||||||
|
@ -176,15 +148,22 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
// Add the stride to the source row
|
// Add the stride to the source row
|
||||||
pSourceRow += sourceData.Stride;
|
pSourceRow += sourceData.Stride;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ClampToByte(int val)
|
private int ClampToByte(int val)
|
||||||
{
|
{
|
||||||
if (val < 0) return 0;
|
if (val < 0)
|
||||||
else if (val > 255) return 255;
|
{
|
||||||
else return val;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val > 255)
|
||||||
|
{
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -198,8 +177,8 @@ namespace BizHawk.Client.EmuHawk
|
||||||
protected virtual void SecondPass(BitmapData sourceData, Bitmap output, int width, int height, Rectangle bounds)
|
protected virtual void SecondPass(BitmapData sourceData, Bitmap output, int width, int height, Rectangle bounds)
|
||||||
{
|
{
|
||||||
BitmapData outputData = null;
|
BitmapData outputData = null;
|
||||||
Color[] pallete = output.Palette.Entries;
|
Color[] palettes = output.Palette.Entries;
|
||||||
int weight = ditherLevel;
|
int weight = DitherLevel;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -209,7 +188,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
// Define the source data pointers. The source row is a byte to
|
// Define the source data pointers. The source row is a byte to
|
||||||
// keep addition of the stride value easier (as this is in bytes)
|
// keep addition of the stride value easier (as this is in bytes)
|
||||||
byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer();
|
byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer();
|
||||||
Int32* pSourcePixel = (Int32*)pSourceRow;
|
int* pSourcePixel = (int*)pSourceRow;
|
||||||
|
|
||||||
// Now define the destination data pointers
|
// Now define the destination data pointers
|
||||||
byte* pDestinationRow = (byte*)outputData.Scan0.ToPointer();
|
byte* pDestinationRow = (byte*)outputData.Scan0.ToPointer();
|
||||||
|
@ -229,13 +208,13 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
if ((row & 1) == 0)
|
if ((row & 1) == 0)
|
||||||
{
|
{
|
||||||
pSourcePixel = (Int32*)pSourceRow;
|
pSourcePixel = (int*)pSourceRow;
|
||||||
pDestinationPixel = pDestinationRow;
|
pDestinationPixel = pDestinationRow;
|
||||||
ptrInc = +1;
|
ptrInc = +1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pSourcePixel = (Int32*)pSourceRow + width - 1;
|
pSourcePixel = (int*)pSourceRow + width - 1;
|
||||||
pDestinationPixel = pDestinationRow + width - 1;
|
pDestinationPixel = pDestinationRow + width - 1;
|
||||||
ptrInc = -1;
|
ptrInc = -1;
|
||||||
}
|
}
|
||||||
|
@ -261,7 +240,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
byte pixelValue = QuantizePixel(target);
|
byte pixelValue = QuantizePixel(target);
|
||||||
*pDestinationPixel = pixelValue;
|
*pDestinationPixel = pixelValue;
|
||||||
|
|
||||||
int actual = pallete[pixelValue].ToArgb();
|
int actual = palettes[pixelValue].ToArgb();
|
||||||
|
|
||||||
int actualR = actual & 0xFF;
|
int actualR = actual & 0xFF;
|
||||||
int actualG = (actual >> 8) & 0xFF;
|
int actualG = (actual >> 8) & 0xFF;
|
||||||
|
@ -314,11 +293,8 @@ namespace BizHawk.Client.EmuHawk
|
||||||
errorNextRowG[width - (col + 1)] += errorGd;
|
errorNextRowG[width - (col + 1)] += errorGd;
|
||||||
errorNextRowB[width - (col + 1)] += errorBd;
|
errorNextRowB[width - (col + 1)] += errorBd;
|
||||||
|
|
||||||
unchecked
|
pSourcePixel += ptrInc;
|
||||||
{
|
pDestinationPixel += ptrInc;
|
||||||
pSourcePixel += ptrInc;
|
|
||||||
pDestinationPixel += ptrInc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the stride to the source row
|
// Add the stride to the source row
|
||||||
|
@ -362,7 +338,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieve the palette for the quantized image
|
/// Retrieve the palette for the quantized image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="original">Any old palette, this is overrwritten</param>
|
/// <param name="original">Any old palette, this is overwritten</param>
|
||||||
/// <returns>The new color palette</returns>
|
/// <returns>The new color palette</returns>
|
||||||
protected abstract ColorPalette GetPalette(ColorPalette original);
|
protected abstract ColorPalette GetPalette(ColorPalette original);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,24 +5,24 @@ namespace BizHawk.Common.NumberExtensions
|
||||||
{
|
{
|
||||||
public static class NumberExtensions
|
public static class NumberExtensions
|
||||||
{
|
{
|
||||||
public static string ToHexString(this int n, int numdigits)
|
public static string ToHexString(this int n, int numDigits)
|
||||||
{
|
{
|
||||||
return string.Format($"{{0:X{numdigits}}}", n);
|
return string.Format($"{{0:X{numDigits}}}", n);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ToHexString(this uint n, int numdigits)
|
public static string ToHexString(this uint n, int numDigits)
|
||||||
{
|
{
|
||||||
return string.Format($"{{0:X{numdigits}}}", n);
|
return string.Format($"{{0:X{numDigits}}}", n);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ToHexString(this long n, int numdigits)
|
public static string ToHexString(this long n, int numDigits)
|
||||||
{
|
{
|
||||||
return string.Format($"{{0:X{numdigits}}}", n);
|
return string.Format($"{{0:X{numDigits}}}", n);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ToHexString(this ulong n, int numdigits)
|
public static string ToHexString(this ulong n, int numDigits)
|
||||||
{
|
{
|
||||||
return string.Format($"{{0:X{numdigits}}}", n);
|
return string.Format($"{{0:X{numDigits}}}", n);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Bit(this byte b, int index)
|
public static bool Bit(this byte b, int index)
|
||||||
|
@ -61,7 +61,7 @@ namespace BizHawk.Common.NumberExtensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static int NumHexDigits(this long i)
|
public static int NumHexDigits(this long i)
|
||||||
{
|
{
|
||||||
// now this is a bit of a trick. if it was less than 0, it mustve been >= 0x80000000 and so takes all 8 digits
|
// now this is a bit of a trick. if it was less than 0, it must have been >= 0x80000000 and so takes all 8 digits
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
{
|
{
|
||||||
return 8;
|
return 8;
|
||||||
|
@ -99,7 +99,7 @@ namespace BizHawk.Common.NumberExtensions
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Force the value to be strictly between min and max (both exclued)
|
/// Force the value to be strictly between min and max (both excluded)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Anything that implements <see cref="IComparable{T}"/></typeparam>
|
/// <typeparam name="T">Anything that implements <see cref="IComparable{T}"/></typeparam>
|
||||||
/// <param name="val">Value that will be clamped</param>
|
/// <param name="val">Value that will be clamped</param>
|
||||||
|
|
|
@ -320,6 +320,7 @@
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Prereqs/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Prereqs/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=prescale/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=prescale/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Quantizer/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Quantizer/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=quantizing/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=quickload/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=quickload/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=quicknes/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=quicknes/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=quicksave/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=quicksave/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|
Loading…
Reference in New Issue