Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
internal static class ProfileResolver
{
/// <summary>
/// Describes the EXIF specific markers.
/// Describes the JFIF specific markers.
/// </summary>
public static readonly byte[] JFifMarker = Encoding.ASCII.GetBytes("JFIF\0");

/// <summary>
/// Describes the EXIF specific markers.
/// Describes the ICC specific markers.
/// </summary>
public static readonly byte[] IccMarker = Encoding.ASCII.GetBytes("ICC_PROFILE\0");

/// <summary>
/// Describes the ICC specific markers.
/// Describes the EXIF specific markers.
/// </summary>
public static readonly byte[] ExifMarker = Encoding.ASCII.GetBytes("Exif\0\0");

Expand All @@ -36,7 +36,7 @@ internal static class ProfileResolver
/// </summary>
/// <param name="bytesToCheck">The bytes to check.</param>
/// <param name="profileIdentifier">The profile identifier.</param>
/// <returns>The <see cref="bool"/></returns>
/// <returns>The <see cref="bool"/>.</returns>
public static bool IsProfile(ReadOnlySpan<byte> bytesToCheck, ReadOnlySpan<byte> profileIdentifier)
{
return bytesToCheck.Length >= profileIdentifier.Length
Expand Down
3 changes: 1 addition & 2 deletions src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Buffers.Binary;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Helpers;
Expand Down Expand Up @@ -726,7 +725,7 @@ private void ProcessStartOfFrameMarker(int remaining, in JpegFileMarker frameMar
this.InputStream.Read(this.temp, 0, length);

// We only support 8-bit and 12-bit precision.
if (!this.supportedPrecisions.Contains(this.temp[0]))
if (Array.IndexOf(this.supportedPrecisions, this.temp[0]) == -1)
{
JpegThrowHelper.ThrowImageFormatException("Only 8-Bit and 12-Bit precision supported.");
}
Expand Down
36 changes: 17 additions & 19 deletions src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Buffers.Binary;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
Expand Down Expand Up @@ -197,7 +196,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream)
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));

ushort max = JpegConstants.MaxLength;
const ushort max = JpegConstants.MaxLength;
if (image.Width >= max || image.Height >= max)
{
throw new ImageFormatException($"Image is too large to encode at {image.Width}x{image.Height}.");
Expand Down Expand Up @@ -226,7 +225,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream)
InitQuantizationTable(1, scale, ref this.chrominanceQuantTable);

// Compute number of components based on input image type.
int componentCount = 3;
const int componentCount = 3;

// Write the Start Of Image marker.
this.WriteApplicationHeader(metadata);
Expand Down Expand Up @@ -278,7 +277,7 @@ private static void WriteDataToDqt(byte[] dqt, ref int offset, QuantIndex i, ref
private static void InitQuantizationTable(int i, int scale, ref Block8x8F quant)
{
DebugGuard.MustBeBetweenOrEqualTo(i, 0, 1, nameof(i));
var unscaledQuant = (i == 0) ? UnscaledQuant_Luminance : UnscaledQuant_Chrominance;
ReadOnlySpan<byte> unscaledQuant = (i == 0) ? UnscaledQuant_Luminance : UnscaledQuant_Chrominance;

for (int j = 0; j < Block8x8F.Size; j++)
{
Expand Down Expand Up @@ -653,8 +652,8 @@ private void WriteExifProfile(ExifProfile exifProfile)
return;
}

const int MaxBytesApp1 = 65533;
const int MaxBytesWithExifId = 65527;
const int MaxBytesApp1 = 65533; // 64k - 2 padding bytes
const int MaxBytesWithExifId = 65527; // Max - 6 bytes for EXIF header.

byte[] data = exifProfile?.ToByteArray();

Expand All @@ -663,31 +662,30 @@ private void WriteExifProfile(ExifProfile exifProfile)
return;
}

data = ProfileResolver.ExifMarker.Concat(data).ToArray();

int remaining = data.Length;
// We can write up to a maximum of 64 data to the initial marker so calculate boundaries.
int exifMarkerLength = ProfileResolver.ExifMarker.Length;
int remaining = exifMarkerLength + data.Length;
int bytesToWrite = remaining > MaxBytesApp1 ? MaxBytesApp1 : remaining;
int app1Length = bytesToWrite + 2;

// Write the app marker, EXIF marker, and data
this.WriteApp1Header(app1Length);

// write the exif data
this.outputStream.Write(data, 0, bytesToWrite);
this.outputStream.Write(ProfileResolver.ExifMarker);
this.outputStream.Write(data, 0, bytesToWrite - exifMarkerLength);
remaining -= bytesToWrite;

// if the exif data exceeds 64K, write it in multiple APP1 Markers
for (int idx = MaxBytesApp1; idx < data.Length; idx += MaxBytesWithExifId)
// If the exif data exceeds 64K, write it in multiple APP1 Markers
for (int idx = MaxBytesWithExifId; idx < data.Length; idx += MaxBytesWithExifId)
{
bytesToWrite = remaining > MaxBytesWithExifId ? MaxBytesWithExifId : remaining;
app1Length = bytesToWrite + 2 + 6;
app1Length = bytesToWrite + 2 + exifMarkerLength;

this.WriteApp1Header(app1Length);

// write Exif00 marker
ProfileResolver.ExifMarker.AsSpan().CopyTo(this.buffer.AsSpan());
this.outputStream.Write(this.buffer, 0, 6);
// Write Exif00 marker
this.outputStream.Write(ProfileResolver.ExifMarker);

// write the exif data
// Write the exif data
this.outputStream.Write(data, idx, bytesToWrite);

remaining -= bytesToWrite;
Expand Down
5 changes: 2 additions & 3 deletions src/ImageSharp/Formats/Png/PngEncoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
Expand Down Expand Up @@ -231,7 +230,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream)
if (this.pngColorType == PngColorType.Palette)
{
byte bits = (byte)this.pngBitDepth;
if (!ColorTypes[this.pngColorType.Value].Contains(bits))
if (Array.IndexOf(ColorTypes[this.pngColorType.Value], bits) == -1)
{
throw new NotSupportedException("Bit depth is not supported or not valid.");
}
Expand Down Expand Up @@ -268,7 +267,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream)
else
{
this.bitDepth = (byte)this.pngBitDepth;
if (!ColorTypes[this.pngColorType.Value].Contains(this.bitDepth))
if (Array.IndexOf(ColorTypes[this.pngColorType.Value], this.bitDepth) == -1)
{
throw new NotSupportedException("Bit depth is not supported or not valid.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.

using System;
using System.Linq;

namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
{
Expand Down Expand Up @@ -52,7 +51,7 @@ public bool Equals(IccOneDimensionalCurve other)
}

return this.BreakPoints.AsSpan().SequenceEqual(other.BreakPoints)
&& this.Segments.SequenceEqual(other.Segments);
&& this.Segments.AsSpan().SequenceEqual(other.Segments);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.

using System;
using System.Linq;
using System.Numerics;

namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
Expand Down Expand Up @@ -65,10 +64,7 @@ public bool Equals(IccResponseCurve other)
}

/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is IccResponseCurve other && this.Equals(other);
}
public override bool Equals(object obj) => obj is IccResponseCurve other && this.Equals(other);

/// <inheritdoc />
public override int GetHashCode()
Expand All @@ -88,7 +84,7 @@ private bool EqualsResponseArray(IccResponseCurve other)

for (int i = 0; i < this.ResponseArrays.Length; i++)
{
if (!this.ResponseArrays[i].SequenceEqual(other.ResponseArrays[i]))
if (!this.ResponseArrays[i].AsSpan().SequenceEqual(other.ResponseArrays[i]))
{
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,7 @@ public int WriteTagDataEntryHeader(IccTypeSignature signature)
/// </summary>
/// <param name="value">The entry to write</param>
/// <returns>The number of bytes written</returns>
public int WriteUnknownTagDataEntry(IccUnknownTagDataEntry value)
{
return this.WriteArray(value.Data);
}
public int WriteUnknownTagDataEntry(IccUnknownTagDataEntry value) => this.WriteArray(value.Data);

/// <summary>
/// Writes a <see cref="IccChromaticityTagDataEntry"/>
Expand Down Expand Up @@ -269,10 +266,7 @@ public int WriteDataTagDataEntry(IccDataTagDataEntry value)
/// </summary>
/// <param name="value">The entry to write</param>
/// <returns>The number of bytes written</returns>
public int WriteDateTimeTagDataEntry(IccDateTimeTagDataEntry value)
{
return this.WriteDateTime(value.Value);
}
public int WriteDateTimeTagDataEntry(IccDateTimeTagDataEntry value) => this.WriteDateTime(value.Value);

/// <summary>
/// Writes a <see cref="IccLut16TagDataEntry"/>
Expand Down Expand Up @@ -563,6 +557,7 @@ public int WriteMultiLocalizedUnicodeTagDataEntry(IccMultiLocalizedUnicodeTagDat
long tpos = this.dataStream.Position;
this.dataStream.Position += cultureCount * 12;

// TODO: Investigate cost of Linq GroupBy
IGrouping<string, IccLocalizedString>[] texts = value.Texts.GroupBy(t => t.Text).ToArray();

uint[] offset = new uint[texts.Length];
Expand Down Expand Up @@ -625,7 +620,7 @@ public int WriteMultiProcessElementsTagDataEntry(IccMultiProcessElementsTagDataE
long tpos = this.dataStream.Position;
this.dataStream.Position += value.Data.Length * 8;

IccPositionNumber[] posTable = new IccPositionNumber[value.Data.Length];
var posTable = new IccPositionNumber[value.Data.Length];
for (int i = 0; i < value.Data.Length; i++)
{
uint offset = (uint)(this.dataStream.Position - start);
Expand Down Expand Up @@ -673,10 +668,7 @@ public int WriteNamedColor2TagDataEntry(IccNamedColor2TagDataEntry value)
/// </summary>
/// <param name="value">The entry to write</param>
/// <returns>The number of bytes written</returns>
public int WriteParametricCurveTagDataEntry(IccParametricCurveTagDataEntry value)
{
return this.WriteParametricCurve(value.Curve);
}
public int WriteParametricCurveTagDataEntry(IccParametricCurveTagDataEntry value) => this.WriteParametricCurve(value.Curve);

/// <summary>
/// Writes a <see cref="IccProfileSequenceDescTagDataEntry"/>
Expand Down Expand Up @@ -793,20 +785,14 @@ public int WriteFix16ArrayTagDataEntry(IccFix16ArrayTagDataEntry value)
/// </summary>
/// <param name="value">The entry to write</param>
/// <returns>The number of bytes written</returns>
public int WriteSignatureTagDataEntry(IccSignatureTagDataEntry value)
{
return this.WriteAsciiString(value.SignatureData, 4, false);
}
public int WriteSignatureTagDataEntry(IccSignatureTagDataEntry value) => this.WriteAsciiString(value.SignatureData, 4, false);

/// <summary>
/// Writes a <see cref="IccTextTagDataEntry"/>
/// </summary>
/// <param name="value">The entry to write</param>
/// <returns>The number of bytes written</returns>
public int WriteTextTagDataEntry(IccTextTagDataEntry value)
{
return this.WriteAsciiString(value.Text);
}
public int WriteTextTagDataEntry(IccTextTagDataEntry value) => this.WriteAsciiString(value.Text);

/// <summary>
/// Writes a <see cref="IccUFix16ArrayTagDataEntry"/>
Expand All @@ -829,40 +815,28 @@ public int WriteUFix16ArrayTagDataEntry(IccUFix16ArrayTagDataEntry value)
/// </summary>
/// <param name="value">The entry to write</param>
/// <returns>The number of bytes written</returns>
public int WriteUInt16ArrayTagDataEntry(IccUInt16ArrayTagDataEntry value)
{
return this.WriteArray(value.Data);
}
public int WriteUInt16ArrayTagDataEntry(IccUInt16ArrayTagDataEntry value) => this.WriteArray(value.Data);

/// <summary>
/// Writes a <see cref="IccUInt32ArrayTagDataEntry"/>
/// </summary>
/// <param name="value">The entry to write</param>
/// <returns>The number of bytes written</returns>
public int WriteUInt32ArrayTagDataEntry(IccUInt32ArrayTagDataEntry value)
{
return this.WriteArray(value.Data);
}
public int WriteUInt32ArrayTagDataEntry(IccUInt32ArrayTagDataEntry value) => this.WriteArray(value.Data);

/// <summary>
/// Writes a <see cref="IccUInt64ArrayTagDataEntry"/>
/// </summary>
/// <param name="value">The entry to write</param>
/// <returns>The number of bytes written</returns>
public int WriteUInt64ArrayTagDataEntry(IccUInt64ArrayTagDataEntry value)
{
return this.WriteArray(value.Data);
}
public int WriteUInt64ArrayTagDataEntry(IccUInt64ArrayTagDataEntry value) => this.WriteArray(value.Data);

/// <summary>
/// Writes a <see cref="IccUInt8ArrayTagDataEntry"/>
/// </summary>
/// <param name="value">The entry to write</param>
/// <returns>The number of bytes written</returns>
public int WriteUInt8ArrayTagDataEntry(IccUInt8ArrayTagDataEntry value)
{
return this.WriteArray(value.Data);
}
public int WriteUInt8ArrayTagDataEntry(IccUInt8ArrayTagDataEntry value) => this.WriteArray(value.Data);

/// <summary>
/// Writes a <see cref="IccViewingConditionsTagDataEntry"/>
Expand Down
1 change: 1 addition & 0 deletions src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ private void WriteTagTable(IccDataWriter writer, IccTagTableEntry[] table)

private IccTagTableEntry[] WriteTagData(IccDataWriter writer, IccTagDataEntry[] entries)
{
// TODO: Investigate cost of Linq GroupBy
IEnumerable<IGrouping<IccTagDataEntry, IccTagDataEntry>> grouped = entries.GroupBy(t => t);

// (Header size) + (entry count) + (nr of entries) * (size of table entry)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.

using System;
using System.Linq;

namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
{
Expand All @@ -17,9 +16,7 @@ internal sealed class IccCurveSetProcessElement : IccMultiProcessElement, IEquat
/// <param name="curves">An array with one dimensional curves</param>
public IccCurveSetProcessElement(IccOneDimensionalCurve[] curves)
: base(IccMultiProcessElementSignature.CurveSet, curves?.Length ?? 1, curves?.Length ?? 1)
{
this.Curves = curves ?? throw new ArgumentNullException(nameof(curves));
}
=> this.Curves = curves ?? throw new ArgumentNullException(nameof(curves));

/// <summary>
/// Gets an array of one dimensional curves
Expand All @@ -31,16 +28,13 @@ public override bool Equals(IccMultiProcessElement other)
{
if (base.Equals(other) && other is IccCurveSetProcessElement element)
{
return this.Curves.SequenceEqual(element.Curves);
return this.Curves.AsSpan().SequenceEqual(element.Curves);
}

return false;
}

/// <inheritdoc />
public bool Equals(IccCurveSetProcessElement other)
{
return this.Equals((IccMultiProcessElement)other);
}
public bool Equals(IccCurveSetProcessElement other) => this.Equals((IccMultiProcessElement)other);
}
}
Loading