PngQuantizer.cs 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. namespace TEAMModelOS.SDK.PngQuant
  5. {
  6. public class PngQuantizer : PngQuantizerBase, IWuQuantizer
  7. {
  8. protected override QuantizedPalette GetQuantizedPalette(int colorCount, ColorData data, IEnumerable<Box> cubes, int alphaThreshold)
  9. {
  10. int imageSize = data.PixelsCount;
  11. LookupData lookups = BuildLookups(cubes, data);
  12. IList<int> quantizedPixels = data.QuantizedPixels;
  13. for (var index = 0; index < imageSize; ++index)
  14. {
  15. var indexParts = BitConverter.GetBytes(quantizedPixels[index]);
  16. quantizedPixels[index] = lookups.Tags[indexParts[Alpha], indexParts[Red], indexParts[Green], indexParts[Blue]];
  17. }
  18. var alphas = new int[colorCount + 1];
  19. var reds = new int[colorCount + 1];
  20. var greens = new int[colorCount + 1];
  21. var blues = new int[colorCount + 1];
  22. var sums = new int[colorCount + 1];
  23. var palette = new QuantizedPalette(imageSize);
  24. IList<Pixel> pixels = data.Pixels;
  25. int pixelsCount = data.PixelsCount;
  26. IList<Lookup> lookupsList = lookups.Lookups;
  27. int lookupsCount = lookupsList.Count;
  28. Dictionary<int, int> cachedMaches = new Dictionary<int, int>();
  29. for (int pixelIndex = 0; pixelIndex < pixelsCount; pixelIndex++)
  30. {
  31. Pixel pixel = pixels[pixelIndex];
  32. palette.PixelIndex[pixelIndex] = -1;
  33. if (pixel.Alpha <= alphaThreshold)
  34. continue;
  35. int argb = pixel.Argb;
  36. if (!cachedMaches.TryGetValue(argb, out int bestMatch))
  37. {
  38. int match = quantizedPixels[pixelIndex];
  39. bestMatch = match;
  40. int bestDistance = int.MaxValue;
  41. for (int lookupIndex = 0; lookupIndex < lookupsCount; lookupIndex++)
  42. {
  43. Lookup lookup = lookupsList[lookupIndex];
  44. var deltaAlpha = pixel.Alpha - lookup.Alpha;
  45. var deltaRed = pixel.Red - lookup.Red;
  46. var deltaGreen = pixel.Green - lookup.Green;
  47. var deltaBlue = pixel.Blue - lookup.Blue;
  48. int distance = deltaAlpha*deltaAlpha + deltaRed*deltaRed + deltaGreen*deltaGreen + deltaBlue*deltaBlue;
  49. if (distance >= bestDistance)
  50. continue;
  51. bestDistance = distance;
  52. bestMatch = lookupIndex;
  53. }
  54. cachedMaches[argb] = bestMatch;
  55. }
  56. alphas[bestMatch] += pixel.Alpha;
  57. reds[bestMatch] += pixel.Red;
  58. greens[bestMatch] += pixel.Green;
  59. blues[bestMatch] += pixel.Blue;
  60. sums[bestMatch]++;
  61. palette.PixelIndex[pixelIndex] = bestMatch;
  62. }
  63. for (var paletteIndex = 0; paletteIndex < colorCount; paletteIndex++)
  64. {
  65. if (sums[paletteIndex] > 0)
  66. {
  67. alphas[paletteIndex] /= sums[paletteIndex];
  68. reds[paletteIndex] /= sums[paletteIndex];
  69. greens[paletteIndex] /= sums[paletteIndex];
  70. blues[paletteIndex] /= sums[paletteIndex];
  71. }
  72. var color = Color.FromArgb(alphas[paletteIndex], reds[paletteIndex], greens[paletteIndex], blues[paletteIndex]);
  73. palette.Colors.Add(color);
  74. }
  75. palette.Colors.Add(Color.FromArgb(0, 0, 0, 0));
  76. return palette;
  77. }
  78. }
  79. }