Skip to content

Commit a4c1a15

Browse files
Fix reviewed issues
1 parent dcc736c commit a4c1a15

4 files changed

Lines changed: 46 additions & 14 deletions

File tree

src/ImageSharp/Color/Color.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public static Color FromPixel<TPixel>(TPixel source)
105105
public static void FromScaledVector(ReadOnlySpan<Vector4> source, Span<Color> destination)
106106
{
107107
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
108-
for (int i = 0; i < destination.Length; i++)
108+
for (int i = 0; i < source.Length; i++)
109109
{
110110
destination[i] = FromScaledVector(source[i]);
111111
}
@@ -127,14 +127,14 @@ public static void FromPixel<TPixel>(ReadOnlySpan<TPixel> source, Span<Color> de
127127
PixelTypeInfo info = TPixel.GetPixelTypeInfo();
128128
if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentBitDepth.Bit32)
129129
{
130-
for (int i = 0; i < destination.Length; i++)
130+
for (int i = 0; i < source.Length; i++)
131131
{
132132
destination[i] = FromScaledVector(source[i].ToScaledVector4());
133133
}
134134
}
135135
else
136136
{
137-
for (int i = 0; i < destination.Length; i++)
137+
for (int i = 0; i < source.Length; i++)
138138
{
139139
destination[i] = new Color(source[i]);
140140
}

src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ internal class PaletteTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
1919
private readonly ushort bitsPerSample1;
2020
private readonly TiffExtraSampleType? extraSamplesType;
2121

22-
private readonly Vector4[] paletteVectors;
22+
private readonly Vector4[] vectorPallete;
23+
private readonly TPixel[] pixelPalette;
24+
2325
private readonly float alphaScale;
2426
private readonly bool hasAlpha;
2527
private Color[]? paletteColors;
@@ -41,7 +43,7 @@ public PaletteTiffColor(TiffBitsPerSample bitsPerSample, ushort[] colorMap, Tiff
4143
int colorCount = 1 << this.bitsPerSample0;
4244

4345
// TIFF PaletteColor uses ColorMap (tag 320 / 0x0140) which is RGB-only (no alpha).
44-
this.paletteVectors = GeneratePaletteVectors(colorMap, colorCount);
46+
this.vectorPallete = GenerateVectorPalette(colorMap, colorCount);
4547

4648
// ExtraSamples (tag 338 / 0x0152) describes extra per-pixel samples stored in the image data stream.
4749
// For PaletteColor, any alpha is per pixel (stored alongside the index), not per palette entry.
@@ -54,10 +56,16 @@ public PaletteTiffColor(TiffBitsPerSample bitsPerSample, ushort[] colorMap, Tiff
5456
{
5557
ulong alphaMax = (1UL << this.bitsPerSample1) - 1;
5658
this.alphaScale = alphaMax > 0 ? 1f / alphaMax : 1f;
59+
this.pixelPalette = [];
60+
}
61+
else
62+
{
63+
// Pre-generate pixel palette for non-alpha case for performance.
64+
this.pixelPalette = GeneratePixelPalette(colorMap, colorCount);
5765
}
5866
}
5967

60-
public Color[] PaletteColors => this.paletteColors ??= GenerateColorPalette(this.paletteVectors);
68+
public Color[] PaletteColors => this.paletteColors ??= GenerateColorPalette(this.vectorPallete);
6169

6270
/// <inheritdoc/>
6371
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
@@ -66,7 +74,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
6674

6775
if (this.hasAlpha)
6876
{
69-
Color[] colors = this.paletteColors ??= GenerateColorPalette(this.paletteVectors);
77+
Color[] colors = this.paletteColors ??= GenerateColorPalette(this.vectorPallete);
7078

7179
// NOTE: ExtraSamples may report "AssociatedAlphaData". For PaletteColor, the stored color sample is the
7280
// palette index, not per-pixel RGB components, so the premultiplication concept is not representable
@@ -81,18 +89,19 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
8189
float alpha = bitReader.ReadBits(this.bitsPerSample1) * this.alphaScale;
8290

8391
// Defensive guard against malformed streams.
84-
if ((uint)index >= (uint)this.paletteVectors.Length)
92+
if ((uint)index >= (uint)this.vectorPallete.Length)
8593
{
8694
index = 0;
8795
}
8896

89-
Vector4 color = this.paletteVectors[index];
97+
Vector4 color = this.vectorPallete[index];
9098
color.W = alpha;
9199

92100
pixelRow[x] = TPixel.FromScaledVector4(color);
93101

94102
// Best-effort palette update for downstream conversions.
95103
// This is intentionally "last writer wins" with no per-pixel branch.
104+
// Performance is not an issue here since the constructor performs no actual transformations.
96105
colors[index] = Color.FromScaledVector(color);
97106
}
98107

@@ -110,19 +119,19 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
110119
int index = bitReader.ReadBits(this.bitsPerSample0);
111120

112121
// Defensive guard against malformed streams.
113-
if ((uint)index >= (uint)this.paletteVectors.Length)
122+
if ((uint)index >= (uint)this.pixelPalette.Length)
114123
{
115124
index = 0;
116125
}
117126

118-
pixelRow[x] = TPixel.FromScaledVector4(this.paletteVectors[index]);
127+
pixelRow[x] = this.pixelPalette[index];
119128
}
120129

121130
bitReader.NextRow();
122131
}
123132
}
124133

125-
private static Vector4[] GeneratePaletteVectors(ushort[] colorMap, int colorCount)
134+
private static Vector4[] GenerateVectorPalette(ushort[] colorMap, int colorCount)
126135
{
127136
Vector4[] palette = new Vector4[colorCount];
128137

@@ -141,6 +150,25 @@ private static Vector4[] GeneratePaletteVectors(ushort[] colorMap, int colorCoun
141150
return palette;
142151
}
143152

153+
private static TPixel[] GeneratePixelPalette(ushort[] colorMap, int colorCount)
154+
{
155+
TPixel[] palette = new TPixel[colorCount];
156+
157+
const int rOffset = 0;
158+
int gOffset = colorCount;
159+
int bOffset = colorCount * 2;
160+
161+
for (int i = 0; i < palette.Length; i++)
162+
{
163+
float r = colorMap[rOffset + i] * InvMax;
164+
float g = colorMap[gOffset + i] * InvMax;
165+
float b = colorMap[bOffset + i] * InvMax;
166+
palette[i] = TPixel.FromScaledVector4(new Vector4(r, g, b, 1f));
167+
}
168+
169+
return palette;
170+
}
171+
144172
private static Color[] GenerateColorPalette(Vector4[] palette)
145173
{
146174
Color[] colors = new Color[palette.Length];

src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ private static void ParseColorType(this TiffDecoderCore options, ExifProfile exi
407407
if (exifProfile.TryGetValue(ExifTag.ColorMap, out IExifValue<ushort[]> value))
408408
{
409409
options.ColorMap = value.Value;
410-
if (options.BitsPerSample.Channels != 1)
410+
if (options.BitsPerSample.Channels is not 1 and not 2)
411411
{
412412
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
413413
}

src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ private TiffFrameMetadata(TiffFrameMetadata other)
3333
this.InkSet = other.InkSet;
3434
this.EncodingWidth = other.EncodingWidth;
3535
this.EncodingHeight = other.EncodingHeight;
36-
this.LocalColorTable = other.LocalColorTable;
36+
37+
if (other.LocalColorTable?.Length > 0)
38+
{
39+
this.LocalColorTable = other.LocalColorTable.Value.ToArray();
40+
}
3741
}
3842

3943
/// <summary>

0 commit comments

Comments
 (0)