Fixed dithering for images with 8-bit alph-channel (closes #8), applied dithering on images loading step to generate previews using dithered image
parent
b5916ab5ba
commit
128a3fa33e
|
@ -4,42 +4,50 @@ namespace Resources.Image
|
||||||
{
|
{
|
||||||
public class ColorError
|
public class ColorError
|
||||||
{
|
{
|
||||||
public const int LowLevel = 0x00;
|
public const byte LowLevel = 0x00;
|
||||||
public const int HighLevel = 0xff;
|
public const byte HighLevel = 0xff;
|
||||||
public const int Treshold = 0x80;
|
public const byte Treshold = 0x80;
|
||||||
|
|
||||||
public ColorError(Color original)
|
public ColorError(Color original)
|
||||||
{
|
{
|
||||||
var r = original.R < Treshold ? LowLevel : HighLevel;
|
var a = NewValue(original.A);
|
||||||
var g = original.G < Treshold ? LowLevel : HighLevel;
|
var r = NewValue(original.R);
|
||||||
var b = original.B < Treshold ? LowLevel : HighLevel;
|
var g = NewValue(original.G);
|
||||||
|
var b = NewValue(original.B);
|
||||||
|
|
||||||
NewColor = Color.FromArgb(original.A, r, g, b);
|
NewColor = Color.FromArgb(a, r, g, b);
|
||||||
|
|
||||||
|
ErrorA = original.A - a;
|
||||||
ErrorR = original.R - r;
|
ErrorR = original.R - r;
|
||||||
ErrorG = original.G - g;
|
ErrorG = original.G - g;
|
||||||
ErrorB = original.B - b;
|
ErrorB = original.B - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color NewColor { get; }
|
public Color NewColor { get; }
|
||||||
|
public int ErrorA { get; }
|
||||||
public int ErrorR { get; }
|
public int ErrorR { get; }
|
||||||
public int ErrorG { get; }
|
public int ErrorG { get; }
|
||||||
public int ErrorB { get; }
|
public int ErrorB { get; }
|
||||||
public bool IsZero => ErrorR == 0 && ErrorG == 0 && ErrorB == 0;
|
public bool IsZero => ErrorA == 0 && ErrorR == 0 && ErrorG == 0 && ErrorB == 0;
|
||||||
|
|
||||||
public Color ApplyError(Color color, int part, int total)
|
public Color ApplyError(Color color, int part, int total)
|
||||||
{
|
{
|
||||||
return Color.FromArgb(
|
return Color.FromArgb(
|
||||||
NewColor.A,
|
CheckBounds(color.A + ErrorA * part / total),
|
||||||
CheckBounds(color.R + ErrorR * part / total),
|
CheckBounds(color.R + ErrorR * part / total),
|
||||||
CheckBounds(color.G + ErrorG * part / total),
|
CheckBounds(color.G + ErrorG * part / total),
|
||||||
CheckBounds(color.B + ErrorB * part / total)
|
CheckBounds(color.B + ErrorB * part / total)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte CheckBounds(int value)
|
private static byte NewValue(byte value)
|
||||||
{
|
{
|
||||||
return (byte) (value < 0 ? 0 : (value > 255 ? 255 : value));
|
return value < Treshold ? LowLevel : HighLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte CheckBounds(int value)
|
||||||
|
{
|
||||||
|
return (byte) (value < LowLevel ? LowLevel : (value > HighLevel ? HighLevel : value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -37,7 +37,6 @@ namespace Resources.Image
|
||||||
_width = (ushort) image.Width;
|
_width = (ushort) image.Width;
|
||||||
_height = (ushort) image.Height;
|
_height = (ushort) image.Height;
|
||||||
|
|
||||||
ApplyDithering();
|
|
||||||
ExtractPalette();
|
ExtractPalette();
|
||||||
|
|
||||||
if (_bitsPerPixel == 3) _bitsPerPixel = 4;
|
if (_bitsPerPixel == 3) _bitsPerPixel = 4;
|
||||||
|
@ -57,17 +56,6 @@ namespace Resources.Image
|
||||||
WriteImage();
|
WriteImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyDithering()
|
|
||||||
{
|
|
||||||
var clone = new Bitmap(_image.Width, _image.Height, PixelFormat.Format32bppArgb);
|
|
||||||
using (var gr = Graphics.FromImage(clone))
|
|
||||||
{
|
|
||||||
gr.DrawImage(_image, new Rectangle(0, 0, clone.Width, clone.Height));
|
|
||||||
}
|
|
||||||
FloydSteinbergDitherer.Process(clone);
|
|
||||||
_image = clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExtractPalette()
|
private void ExtractPalette()
|
||||||
{
|
{
|
||||||
Logger.Trace("Extracting palette...");
|
Logger.Trace("Extracting palette...");
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using Resources.Image;
|
||||||
|
|
||||||
namespace Resources
|
namespace Resources
|
||||||
{
|
{
|
||||||
|
@ -27,11 +29,25 @@ namespace Resources
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var image = (Bitmap) System.Drawing.Image.FromFile(fullFileName);
|
||||||
Logger.Trace("Image was loaded from file {0}", fullFileName);
|
Logger.Trace("Image was loaded from file {0}", fullFileName);
|
||||||
return (Bitmap) System.Drawing.Image.FromFile(fullFileName);
|
return ApplyDithering(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new FileNotFoundException($"File referenced by index {index} not found.");
|
throw new FileNotFoundException($"File referenced by index {index} not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Bitmap ApplyDithering(Bitmap image)
|
||||||
|
{
|
||||||
|
var clone = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb);
|
||||||
|
using (var gr = Graphics.FromImage(clone))
|
||||||
|
{
|
||||||
|
gr.DrawImage(image, new Rectangle(0, 0, clone.Width, clone.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
FloydSteinbergDitherer.Process(clone);
|
||||||
|
clone.Save("tmp.png");
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue