Skip to content

Commit b54db18

Browse files
Merge branch 'main' into fix-async-image-load
2 parents 2745cf8 + f970634 commit b54db18

26 files changed

+575
-264
lines changed

src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ private void ProcessApplicationHeaderMarker(BufferedReadStream stream, int remai
677677
}
678678

679679
/// <summary>
680-
/// Processes the App1 marker retrieving any stored metadata
680+
/// Processes the App1 marker retrieving any stored metadata.
681681
/// </summary>
682682
/// <param name="stream">The input stream.</param>
683683
/// <param name="remaining">The remaining bytes in the segment block.</param>
@@ -687,7 +687,7 @@ private void ProcessApp1Marker(BufferedReadStream stream, int remaining)
687687
const int XmpMarkerLength = 29;
688688
if (remaining < ExifMarkerLength || this.IgnoreMetadata)
689689
{
690-
// Skip the application header length
690+
// Skip the application header length.
691691
stream.Skip(remaining);
692692
return;
693693
}
@@ -697,12 +697,12 @@ private void ProcessApp1Marker(BufferedReadStream stream, int remaining)
697697
JpegThrowHelper.ThrowInvalidImageContentException("Bad App1 Marker length.");
698698
}
699699

700-
// XMP marker is the longest, so read at least that many bytes into temp.
700+
// XMP marker is the longer then the EXIF marker, so first try read the EXIF marker bytes.
701701
stream.Read(this.temp, 0, ExifMarkerLength);
702+
remaining -= ExifMarkerLength;
702703

703704
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.ExifMarker))
704705
{
705-
remaining -= ExifMarkerLength;
706706
this.hasExif = true;
707707
byte[] profile = new byte[remaining];
708708
stream.Read(profile, 0, remaining);
@@ -713,7 +713,7 @@ private void ProcessApp1Marker(BufferedReadStream stream, int remaining)
713713
}
714714
else
715715
{
716-
// If the EXIF information exceeds 64K, it will be split over multiple APP1 markers
716+
// If the EXIF information exceeds 64K, it will be split over multiple APP1 markers.
717717
this.ExtendProfile(ref this.exifData, profile);
718718
}
719719

@@ -722,9 +722,10 @@ private void ProcessApp1Marker(BufferedReadStream stream, int remaining)
722722

723723
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.XmpMarker.Slice(0, ExifMarkerLength)))
724724
{
725-
stream.Read(this.temp, 0, XmpMarkerLength - ExifMarkerLength);
726-
remaining -= XmpMarkerLength;
727-
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.XmpMarker.Slice(ExifMarkerLength)))
725+
int remainingXmpMarkerBytes = XmpMarkerLength - ExifMarkerLength;
726+
stream.Read(this.temp, ExifMarkerLength, remainingXmpMarkerBytes);
727+
remaining -= remainingXmpMarkerBytes;
728+
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.XmpMarker))
728729
{
729730
this.hasXmp = true;
730731
byte[] profile = new byte[remaining];
@@ -736,7 +737,7 @@ private void ProcessApp1Marker(BufferedReadStream stream, int remaining)
736737
}
737738
else
738739
{
739-
// If the XMP information exceeds 64K, it will be split over multiple APP1 markers
740+
// If the XMP information exceeds 64K, it will be split over multiple APP1 markers.
740741
this.ExtendProfile(ref this.xmpData, profile);
741742
}
742743

src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs

Lines changed: 221 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ internal static class HorizontalPredictor
2222
/// <param name="pixelBytes">Buffer with decompressed pixel data.</param>
2323
/// <param name="width">The width of the image or strip.</param>
2424
/// <param name="colorType">The color type of the pixel data.</param>
25-
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
25+
/// <param name="isBigEndian">If set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
2626
public static void Undo(Span<byte> pixelBytes, int width, TiffColorType colorType, bool isBigEndian)
2727
{
2828
switch (colorType)
@@ -43,12 +43,21 @@ public static void Undo(Span<byte> pixelBytes, int width, TiffColorType colorTyp
4343
case TiffColorType.Rgb888:
4444
UndoRgb24Bit(pixelBytes, width);
4545
break;
46+
case TiffColorType.Rgba8888:
47+
UndoRgba32Bit(pixelBytes, width);
48+
break;
4649
case TiffColorType.Rgb161616:
4750
UndoRgb48Bit(pixelBytes, width, isBigEndian);
4851
break;
52+
case TiffColorType.Rgba16161616:
53+
UndoRgba64Bit(pixelBytes, width, isBigEndian);
54+
break;
4955
case TiffColorType.Rgb323232:
5056
UndoRgb96Bit(pixelBytes, width, isBigEndian);
5157
break;
58+
case TiffColorType.Rgba32323232:
59+
UndoRgba128Bit(pixelBytes, width, isBigEndian);
60+
break;
5261
}
5362
}
5463

@@ -243,6 +252,33 @@ private static void UndoRgb24Bit(Span<byte> pixelBytes, int width)
243252
}
244253
}
245254

255+
private static void UndoRgba32Bit(Span<byte> pixelBytes, int width)
256+
{
257+
int rowBytesCount = width * 4;
258+
int height = pixelBytes.Length / rowBytesCount;
259+
for (int y = 0; y < height; y++)
260+
{
261+
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
262+
Span<Rgba32> rowRgb = MemoryMarshal.Cast<byte, Rgba32>(rowBytes).Slice(0, width);
263+
ref Rgba32 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb);
264+
byte r = rowRgbBase.R;
265+
byte g = rowRgbBase.G;
266+
byte b = rowRgbBase.B;
267+
byte a = rowRgbBase.A;
268+
269+
for (int x = 1; x < rowRgb.Length; x++)
270+
{
271+
ref Rgba32 pixel = ref rowRgb[x];
272+
r += pixel.R;
273+
g += pixel.G;
274+
b += pixel.B;
275+
a += pixel.A;
276+
var rgb = new Rgba32(r, g, b, a);
277+
pixel.FromRgba32(rgb);
278+
}
279+
}
280+
}
281+
246282
private static void UndoRgb48Bit(Span<byte> pixelBytes, int width, bool isBigEndian)
247283
{
248284
int rowBytesCount = width * 6;
@@ -319,6 +355,98 @@ private static void UndoRgb48Bit(Span<byte> pixelBytes, int width, bool isBigEnd
319355
}
320356
}
321357

358+
private static void UndoRgba64Bit(Span<byte> pixelBytes, int width, bool isBigEndian)
359+
{
360+
int rowBytesCount = width * 8;
361+
int height = pixelBytes.Length / rowBytesCount;
362+
if (isBigEndian)
363+
{
364+
for (int y = 0; y < height; y++)
365+
{
366+
int offset = 0;
367+
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
368+
ushort r = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
369+
offset += 2;
370+
ushort g = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
371+
offset += 2;
372+
ushort b = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
373+
offset += 2;
374+
ushort a = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
375+
offset += 2;
376+
377+
for (int x = 1; x < width; x++)
378+
{
379+
Span<byte> rowSpan = rowBytes.Slice(offset, 2);
380+
ushort deltaR = TiffUtils.ConvertToUShortBigEndian(rowSpan);
381+
r += deltaR;
382+
BinaryPrimitives.WriteUInt16BigEndian(rowSpan, r);
383+
offset += 2;
384+
385+
rowSpan = rowBytes.Slice(offset, 2);
386+
ushort deltaG = TiffUtils.ConvertToUShortBigEndian(rowSpan);
387+
g += deltaG;
388+
BinaryPrimitives.WriteUInt16BigEndian(rowSpan, g);
389+
offset += 2;
390+
391+
rowSpan = rowBytes.Slice(offset, 2);
392+
ushort deltaB = TiffUtils.ConvertToUShortBigEndian(rowSpan);
393+
b += deltaB;
394+
BinaryPrimitives.WriteUInt16BigEndian(rowSpan, b);
395+
offset += 2;
396+
397+
rowSpan = rowBytes.Slice(offset, 2);
398+
ushort deltaA = TiffUtils.ConvertToUShortBigEndian(rowSpan);
399+
a += deltaA;
400+
BinaryPrimitives.WriteUInt16BigEndian(rowSpan, a);
401+
offset += 2;
402+
}
403+
}
404+
}
405+
else
406+
{
407+
for (int y = 0; y < height; y++)
408+
{
409+
int offset = 0;
410+
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
411+
ushort r = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
412+
offset += 2;
413+
ushort g = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
414+
offset += 2;
415+
ushort b = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
416+
offset += 2;
417+
ushort a = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
418+
offset += 2;
419+
420+
for (int x = 1; x < width; x++)
421+
{
422+
Span<byte> rowSpan = rowBytes.Slice(offset, 2);
423+
ushort deltaR = TiffUtils.ConvertToUShortLittleEndian(rowSpan);
424+
r += deltaR;
425+
BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, r);
426+
offset += 2;
427+
428+
rowSpan = rowBytes.Slice(offset, 2);
429+
ushort deltaG = TiffUtils.ConvertToUShortLittleEndian(rowSpan);
430+
g += deltaG;
431+
BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, g);
432+
offset += 2;
433+
434+
rowSpan = rowBytes.Slice(offset, 2);
435+
ushort deltaB = TiffUtils.ConvertToUShortLittleEndian(rowSpan);
436+
b += deltaB;
437+
BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, b);
438+
offset += 2;
439+
440+
rowSpan = rowBytes.Slice(offset, 2);
441+
ushort deltaA = TiffUtils.ConvertToUShortLittleEndian(rowSpan);
442+
a += deltaA;
443+
BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, a);
444+
offset += 2;
445+
}
446+
}
447+
}
448+
}
449+
322450
private static void UndoRgb96Bit(Span<byte> pixelBytes, int width, bool isBigEndian)
323451
{
324452
int rowBytesCount = width * 12;
@@ -394,5 +522,97 @@ private static void UndoRgb96Bit(Span<byte> pixelBytes, int width, bool isBigEnd
394522
}
395523
}
396524
}
525+
526+
private static void UndoRgba128Bit(Span<byte> pixelBytes, int width, bool isBigEndian)
527+
{
528+
int rowBytesCount = width * 16;
529+
int height = pixelBytes.Length / rowBytesCount;
530+
if (isBigEndian)
531+
{
532+
for (int y = 0; y < height; y++)
533+
{
534+
int offset = 0;
535+
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
536+
uint r = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
537+
offset += 4;
538+
uint g = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
539+
offset += 4;
540+
uint b = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
541+
offset += 4;
542+
uint a = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
543+
offset += 4;
544+
545+
for (int x = 1; x < width; x++)
546+
{
547+
Span<byte> rowSpan = rowBytes.Slice(offset, 4);
548+
uint deltaR = TiffUtils.ConvertToUIntBigEndian(rowSpan);
549+
r += deltaR;
550+
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r);
551+
offset += 4;
552+
553+
rowSpan = rowBytes.Slice(offset, 4);
554+
uint deltaG = TiffUtils.ConvertToUIntBigEndian(rowSpan);
555+
g += deltaG;
556+
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g);
557+
offset += 4;
558+
559+
rowSpan = rowBytes.Slice(offset, 4);
560+
uint deltaB = TiffUtils.ConvertToUIntBigEndian(rowSpan);
561+
b += deltaB;
562+
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b);
563+
offset += 4;
564+
565+
rowSpan = rowBytes.Slice(offset, 4);
566+
uint deltaA = TiffUtils.ConvertToUIntBigEndian(rowSpan);
567+
a += deltaA;
568+
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, a);
569+
offset += 4;
570+
}
571+
}
572+
}
573+
else
574+
{
575+
for (int y = 0; y < height; y++)
576+
{
577+
int offset = 0;
578+
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
579+
uint r = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
580+
offset += 4;
581+
uint g = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
582+
offset += 4;
583+
uint b = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
584+
offset += 4;
585+
uint a = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
586+
offset += 4;
587+
588+
for (int x = 1; x < width; x++)
589+
{
590+
Span<byte> rowSpan = rowBytes.Slice(offset, 4);
591+
uint deltaR = TiffUtils.ConvertToUIntLittleEndian(rowSpan);
592+
r += deltaR;
593+
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r);
594+
offset += 4;
595+
596+
rowSpan = rowBytes.Slice(offset, 4);
597+
uint deltaG = TiffUtils.ConvertToUIntLittleEndian(rowSpan);
598+
g += deltaG;
599+
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g);
600+
offset += 4;
601+
602+
rowSpan = rowBytes.Slice(offset, 4);
603+
uint deltaB = TiffUtils.ConvertToUIntLittleEndian(rowSpan);
604+
b += deltaB;
605+
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b);
606+
offset += 4;
607+
608+
rowSpan = rowBytes.Slice(offset, 4);
609+
uint deltaA = TiffUtils.ConvertToUIntLittleEndian(rowSpan);
610+
a += deltaA;
611+
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, a);
612+
offset += 4;
613+
}
614+
}
615+
}
616+
}
397617
}
398618
}

src/ImageSharp/ImageFrame{TPixel}.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,10 +362,8 @@ internal override void CopyPixelsTo<TDestinationPixel>(MemoryGroup<TDestinationP
362362
return;
363363
}
364364

365-
this.PixelBuffer.FastMemoryGroup.TransformTo(destination, (s, d) =>
366-
{
367-
PixelOperations<TPixel>.Instance.To(this.GetConfiguration(), s, d);
368-
});
365+
this.PixelBuffer.FastMemoryGroup.TransformTo(destination, (s, d)
366+
=> PixelOperations<TPixel>.Instance.To(this.GetConfiguration(), s, d));
369367
}
370368

371369
/// <inheritdoc/>

src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public abstract partial class ExifTag
9494
/// <summary>
9595
/// Gets the MDFileUnits exif tag.
9696
/// </summary>
97-
public static ExifTag<string> MDFileUnits => new ExifTag<string>(ExifTagValue.MDFileUnits);
97+
public static ExifTag<string> MDFileUnits { get; } = new ExifTag<string>(ExifTagValue.MDFileUnits);
9898

9999
/// <summary>
100100
/// Gets the SEMInfo exif tag.

src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ internal ExifValue(ExifValue other)
2929
{
3030
// All array types are value types so Clone() is sufficient here.
3131
var array = (Array)other.GetValue();
32-
this.TrySetValue(array.Clone());
32+
this.TrySetValue(array?.Clone());
3333
}
3434
}
3535

src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public partial struct RgbaVector
2121
internal class PixelOperations : PixelOperations<RgbaVector>
2222
{
2323
private static readonly Lazy<PixelTypeInfo> LazyInfo =
24-
new Lazy<PixelTypeInfo>(() => PixelTypeInfo.Create<RgbaVector>(PixelAlphaRepresentation.Unassociated), true);
24+
new(() => PixelTypeInfo.Create<RgbaVector>(PixelAlphaRepresentation.Unassociated), true);
2525

2626
/// <inheritdoc />
2727
public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value;
@@ -34,7 +34,7 @@ public override void From<TSourcePixel>(
3434
{
3535
Span<Vector4> destinationVectors = MemoryMarshal.Cast<RgbaVector, Vector4>(destinationPixels);
3636

37-
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, sourcePixels, destinationVectors);
37+
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, sourcePixels, destinationVectors, PixelConversionModifiers.Scale);
3838
}
3939

4040
/// <inheritdoc />

0 commit comments

Comments
 (0)