Этап 5
This commit is contained in:
@@ -21,6 +21,13 @@ public sealed class MinintDocument
|
||||
|
||||
public List<MinintLayer> Layers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Reverse lookup cache: RgbaColor → palette index. Built lazily, invalidated
|
||||
/// on structural palette changes (compact, clear). Call <see cref="InvalidatePaletteCache"/>
|
||||
/// after bulk palette modifications.
|
||||
/// </summary>
|
||||
private Dictionary<RgbaColor, int>? _paletteCache;
|
||||
|
||||
public MinintDocument(string name)
|
||||
{
|
||||
Name = name;
|
||||
@@ -50,4 +57,48 @@ public sealed class MinintDocument
|
||||
<= 16_777_215 => 3,
|
||||
_ => 4
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// O(1) lookup of a color in the palette. Returns the index, or -1 if not found.
|
||||
/// Lazily builds an internal dictionary on first call.
|
||||
/// </summary>
|
||||
public int FindColorCached(RgbaColor color)
|
||||
{
|
||||
var cache = EnsurePaletteCache();
|
||||
return cache.TryGetValue(color, out int idx) ? idx : -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the index of <paramref name="color"/>. If absent, appends it to the palette
|
||||
/// and updates the cache. O(1) amortized.
|
||||
/// </summary>
|
||||
public int EnsureColorCached(RgbaColor color)
|
||||
{
|
||||
var cache = EnsurePaletteCache();
|
||||
if (cache.TryGetValue(color, out int idx))
|
||||
return idx;
|
||||
|
||||
idx = Palette.Count;
|
||||
Palette.Add(color);
|
||||
cache[color] = idx;
|
||||
return idx;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops the reverse lookup cache. Must be called after any operation that
|
||||
/// reorders, removes, or bulk-replaces palette entries (e.g. compact, grayscale).
|
||||
/// </summary>
|
||||
public void InvalidatePaletteCache() => _paletteCache = null;
|
||||
|
||||
private Dictionary<RgbaColor, int> EnsurePaletteCache()
|
||||
{
|
||||
if (_paletteCache is not null)
|
||||
return _paletteCache;
|
||||
|
||||
var cache = new Dictionary<RgbaColor, int>(Palette.Count);
|
||||
for (int i = 0; i < Palette.Count; i++)
|
||||
cache.TryAdd(Palette[i], i); // first occurrence wins (for dupes)
|
||||
_paletteCache = cache;
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,26 +5,10 @@ namespace Minint.Core.Services.Impl;
|
||||
public sealed class PaletteService : IPaletteService
|
||||
{
|
||||
public int FindColor(MinintDocument document, RgbaColor color)
|
||||
{
|
||||
var palette = document.Palette;
|
||||
for (int i = 0; i < palette.Count; i++)
|
||||
{
|
||||
if (palette[i] == color)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
=> document.FindColorCached(color);
|
||||
|
||||
public int EnsureColor(MinintDocument document, RgbaColor color)
|
||||
{
|
||||
int idx = FindColor(document, color);
|
||||
if (idx >= 0)
|
||||
return idx;
|
||||
|
||||
idx = document.Palette.Count;
|
||||
document.Palette.Add(color);
|
||||
return idx;
|
||||
}
|
||||
=> document.EnsureColorCached(color);
|
||||
|
||||
public void CompactPalette(MinintDocument document)
|
||||
{
|
||||
@@ -32,19 +16,16 @@ public sealed class PaletteService : IPaletteService
|
||||
if (palette.Count <= 1)
|
||||
return;
|
||||
|
||||
// 1. Collect indices actually used across all layers
|
||||
var usedIndices = new HashSet<int> { 0 }; // always keep transparent
|
||||
var usedIndices = new HashSet<int> { 0 };
|
||||
foreach (var layer in document.Layers)
|
||||
{
|
||||
foreach (int idx in layer.Pixels)
|
||||
usedIndices.Add(idx);
|
||||
}
|
||||
|
||||
// 2. Build new palette and old→new mapping
|
||||
var oldToNew = new int[palette.Count];
|
||||
var newPalette = new List<RgbaColor>(usedIndices.Count);
|
||||
|
||||
// Index 0 (transparent) stays at 0
|
||||
newPalette.Add(palette[0]);
|
||||
oldToNew[0] = 0;
|
||||
|
||||
@@ -55,23 +36,21 @@ public sealed class PaletteService : IPaletteService
|
||||
oldToNew[i] = newPalette.Count;
|
||||
newPalette.Add(palette[i]);
|
||||
}
|
||||
// unused indices don't get a mapping — they'll never be looked up
|
||||
}
|
||||
|
||||
// 3. If nothing was removed, skip the remap
|
||||
if (newPalette.Count == palette.Count)
|
||||
return;
|
||||
|
||||
// 4. Replace palette
|
||||
palette.Clear();
|
||||
palette.AddRange(newPalette);
|
||||
|
||||
// 5. Remap all pixel arrays
|
||||
foreach (var layer in document.Layers)
|
||||
{
|
||||
var px = layer.Pixels;
|
||||
for (int i = 0; i < px.Length; i++)
|
||||
px[i] = oldToNew[px[i]];
|
||||
}
|
||||
|
||||
document.InvalidatePaletteCache();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user