diff --git a/src/ImageSharp/Formats/DecoderOptions.cs b/src/ImageSharp/Formats/DecoderOptions.cs index f1925913ce..916888af33 100644 --- a/src/ImageSharp/Formats/DecoderOptions.cs +++ b/src/ImageSharp/Formats/DecoderOptions.cs @@ -78,7 +78,7 @@ public sealed class DecoderOptions return false; } - if (this.ColorProfileHandling != ColorProfileHandling.Convert) + if (this.ColorProfileHandling == ColorProfileHandling.Preserve) { return false; } diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1CodecConfiguration.cs b/src/ImageSharp/Formats/Heif/Av1/Av1CodecConfiguration.cs index 5e39a3f5d7..9ec06fc916 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Av1CodecConfiguration.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Av1CodecConfiguration.cs @@ -382,7 +382,7 @@ internal sealed class Av1CodecConfiguration contentLightLevel = dataObuContentLightLevel ?? this.configContentLightLevel; masteringDisplayColorVolume = dataObuMasteringDisplayColorVolume ?? this.configMasteringDisplayColorVolume; } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(options, ex)) { // Conflicting optional OBU metadata is discarded without weakening OBU framing or sequence-header checks. } @@ -563,7 +563,7 @@ internal sealed class Av1CodecConfiguration masteringDisplayColorVolume = obuMasteringDisplayColorVolume; } } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(options, ex)) { // The OBU payload remains bounded by the image-data scan; only its invalid optional metadata is discarded. } diff --git a/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1IntraSuperblockEncoder.ModeDecision.cs b/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1IntraSuperblockEncoder.ModeDecision.cs index 324d1866bb..5cdd79ecf0 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1IntraSuperblockEncoder.ModeDecision.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1IntraSuperblockEncoder.ModeDecision.cs @@ -88,7 +88,7 @@ internal static partial class Av1IntraSuperblockEncoder ref int partitionIndex) { Av1EncoderCommon common = picture.Parent.Common; - Point modeInfoPosition = blockOrigin >> Av1Constants.ModeInfoSizeLog2; + Point modeInfoPosition = new(blockOrigin.X >> Av1Constants.ModeInfoSizeLog2, blockOrigin.Y >> Av1Constants.ModeInfoSizeLog2); if (modeInfoPosition.Y >= common.ModeInfoRowCount || modeInfoPosition.X >= common.ModeInfoColumnCount) { return; @@ -219,7 +219,7 @@ internal static partial class Av1IntraSuperblockEncoder return preparedPartition; } - Point modeInfoPosition = blockOrigin >> Av1Constants.ModeInfoSizeLog2; + Point modeInfoPosition = new(blockOrigin.X >> Av1Constants.ModeInfoSizeLog2, blockOrigin.Y >> Av1Constants.ModeInfoSizeLog2); bool hasRows = modeInfoPosition.Y + blockSize.Get4x4HighCount() <= this.picture.Parent.Common.ModeInfoRowCount; @@ -479,7 +479,7 @@ internal static partial class Av1IntraSuperblockEncoder private bool IsBlockOriginInsideFrame(Point blockOrigin) { - Point modeInfoPosition = blockOrigin >> Av1Constants.ModeInfoSizeLog2; + Point modeInfoPosition = new(blockOrigin.X >> Av1Constants.ModeInfoSizeLog2, blockOrigin.Y >> Av1Constants.ModeInfoSizeLog2); return modeInfoPosition.Y < this.picture.Parent.Common.ModeInfoRowCount && modeInfoPosition.X < this.picture.Parent.Common.ModeInfoColumnCount; } @@ -596,7 +596,7 @@ internal static partial class Av1IntraSuperblockEncoder }; modeInfo.CdefStrength = 0; - Point modeInfoPosition = blockOrigin >> Av1Constants.ModeInfoSizeLog2; + Point modeInfoPosition = new(blockOrigin.X >> Av1Constants.ModeInfoSizeLog2, blockOrigin.Y >> Av1Constants.ModeInfoSizeLog2); block.HasChroma = !this.source.IsMonochrome && Av1TileReader.HasChroma(this.picture.Sequence.SequenceHeader, modeInfoPosition, blockSize); @@ -768,7 +768,7 @@ internal static partial class Av1IntraSuperblockEncoder { // Trial leaves must use the same reconstruction order as final leaves of this partition. this.SetBlockGeometry(blockOrigin, blockSize, partitionType); - Point modeInfoPosition = blockOrigin >> Av1Constants.ModeInfoSizeLog2; + Point modeInfoPosition = new(blockOrigin.X >> Av1Constants.ModeInfoSizeLog2, blockOrigin.Y >> Av1Constants.ModeInfoSizeLog2); Av1TileWriter.SetModeInfoRowAndColumn( this.picture, macroBlock, @@ -813,7 +813,7 @@ internal static partial class Av1IntraSuperblockEncoder Av1BlockSize blockSize, Av1PartitionType partitionType) { - Point modeInfoPosition = blockOrigin >> Av1Constants.ModeInfoSizeLog2; + Point modeInfoPosition = new(blockOrigin.X >> Av1Constants.ModeInfoSizeLog2, blockOrigin.Y >> Av1Constants.ModeInfoSizeLog2); ref Av1MacroBlockModeInfo modeInfo = ref this.picture.GetMacroBlockModeInfo(modeInfoPosition); modeInfo.Block = new Av1EncoderBlockModeInfo { diff --git a/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1IntraSuperblockEncoder.ReferenceModeDecision.cs b/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1IntraSuperblockEncoder.ReferenceModeDecision.cs index 717d3c19fe..a5223e8918 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1IntraSuperblockEncoder.ReferenceModeDecision.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1IntraSuperblockEncoder.ReferenceModeDecision.cs @@ -480,7 +480,7 @@ internal static partial class Av1IntraSuperblockEncoder this.blockWorkspace.GetInterPredictionWorkspace(); ObuFrameHeader frameHeader = this.picture.Parent.FrameHeader; - Point modeInfoPosition = blockOrigin >> Av1Constants.ModeInfoSizeLog2; + Point modeInfoPosition = new(blockOrigin.X >> Av1Constants.ModeInfoSizeLog2, blockOrigin.Y >> Av1Constants.ModeInfoSizeLog2); ref Av1ReferenceMotionVectors referenceMotionVectors = ref this.blockWorkspace.ReferenceMotionVectors; referenceMotionVectors.Build( this.picture, diff --git a/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1IntraSuperblockEncoder.cs b/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1IntraSuperblockEncoder.cs index e815a89ce5..5375f9681c 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1IntraSuperblockEncoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1IntraSuperblockEncoder.cs @@ -187,7 +187,7 @@ internal static partial class Av1IntraSuperblockEncoder public void EncodePartitionTree(Point blockOrigin, Av1BlockSize blockSize) { Av1EncoderCommon common = this.picture.Parent.Common; - Point modeInfoPosition = blockOrigin >> Av1Constants.ModeInfoSizeLog2; + Point modeInfoPosition = new(blockOrigin.X >> Av1Constants.ModeInfoSizeLog2, blockOrigin.Y >> Av1Constants.ModeInfoSizeLog2); if (modeInfoPosition.Y >= common.ModeInfoRowCount || modeInfoPosition.X >= common.ModeInfoColumnCount) { return; diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileWriter.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileWriter.cs index e1cebda557..2233f58794 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileWriter.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileWriter.cs @@ -282,7 +282,7 @@ internal partial class Av1TileWriter (childIndex & 1) * halfBlockSize, (childIndex >> 1) * halfBlockSize); - Point childModeInfoPosition = childOrigin >> Av1Constants.ModeInfoSizeLog2; + Point childModeInfoPosition = new(childOrigin.X >> Av1Constants.ModeInfoSizeLog2, childOrigin.Y >> Av1Constants.ModeInfoSizeLog2); if (childModeInfoPosition.Y >= common.ModeInfoRowCount || childModeInfoPosition.X >= common.ModeInfoColumnCount) { @@ -791,7 +791,7 @@ internal partial class Av1TileWriter out bool hasColumns) { int halfBlockModeInfoCount = blockSize.Get4x4WideCount() >> 1; - Point modeInfoPosition = blockOrigin >> Av1Constants.ModeInfoSizeLog2; + Point modeInfoPosition = new(blockOrigin.X >> Av1Constants.ModeInfoSizeLog2, blockOrigin.Y >> Av1Constants.ModeInfoSizeLog2); hasRows = modeInfoPosition.Y + halfBlockModeInfoCount < pcs.Parent.Common.ModeInfoRowCount; hasColumns = modeInfoPosition.X + halfBlockModeInfoCount < pcs.Parent.Common.ModeInfoColumnCount; int leftIndex = partitionContexts.GetLeftIndex(blockOrigin); @@ -2024,7 +2024,7 @@ internal partial class Av1TileWriter Av1NeighborArrayUnit luma_dc_sign_level_coeff_na = pcs.LuminanceDcSignLevelCoefficientNeighbors[tile_idx]; Av1NeighborArrayUnit cr_dc_sign_level_coeff_na = pcs.CrDcSignLevelCoefficientNeighbors[tile_idx]; Av1NeighborArrayUnit cb_dc_sign_level_coeff_na = pcs.CbDcSignLevelCoefficientNeighbors[tile_idx]; - Point modeInfoPosition = blockOrigin >> Av1Constants.ModeInfoSizeLog2; + Point modeInfoPosition = new(blockOrigin.X >> Av1Constants.ModeInfoSizeLog2, blockOrigin.Y >> Av1Constants.ModeInfoSizeLog2); ref Av1MacroBlockModeInfo mbmi = ref pcs.GetMacroBlockModeInfo(modeInfoPosition); bool skip_coeff = mbmi.Block.Skip; diff --git a/src/ImageSharp/Formats/Heif/HeifDecoderCore.cs b/src/ImageSharp/Formats/Heif/HeifDecoderCore.cs index 0c054b84d5..80f622af43 100644 --- a/src/ImageSharp/Formats/Heif/HeifDecoderCore.cs +++ b/src/ImageSharp/Formats/Heif/HeifDecoderCore.cs @@ -1289,12 +1289,12 @@ internal sealed class HeifDecoderCore : ImageDecoderCore this.itemLinks.Add(link); } - catch (Exception ex) when (linkType == Heif4CharCode.Cdsc && ImageDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) + catch (Exception ex) when (linkType == Heif4CharCode.Cdsc && HeifDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) { // A malformed descriptive link cannot change reconstructed pixels, so non-strict modes omit it. bytesRead = referenceEnd; } - catch (Exception ex) when (linkType != Heif4CharCode.Cdsc && ImageDecoderCore.ShouldIgnoreImageDataSegmentError(this.Options, ex)) + catch (Exception ex) when (linkType != Heif4CharCode.Cdsc && HeifDecoderCore.ShouldIgnoreImageDataSegmentError(this.Options, ex)) { // IgnoreImageData permits a malformed optional image relationship to be omitted while retaining // independently reconstructable items and thumbnail fallbacks. @@ -1440,7 +1440,7 @@ internal sealed class HeifDecoderCore : ImageDecoderCore { iccProfile = HeifPropertyParser.ParseIccProfile(profileData); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) { // Keep the understood property index without retaining invalid ancillary metadata. } @@ -1482,7 +1482,7 @@ internal sealed class HeifDecoderCore : ImageDecoderCore { pixelAspectRatio = HeifPropertyParser.ParsePixelAspectRatio(boxBuffer); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) { // Keep the understood property index without retaining invalid ancillary metadata. } @@ -1555,7 +1555,7 @@ internal sealed class HeifDecoderCore : ImageDecoderCore { contentLightLevel = HeifPropertyParser.ParseContentLightLevel(boxBuffer); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) { // Keep the understood property index without retaining invalid ancillary metadata. } @@ -1568,7 +1568,7 @@ internal sealed class HeifDecoderCore : ImageDecoderCore { masteringDisplayColorVolume = HeifPropertyParser.ParseMasteringDisplayColorVolume(boxBuffer); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) { // Keep the understood property index without retaining invalid ancillary metadata. } @@ -1581,7 +1581,7 @@ internal sealed class HeifDecoderCore : ImageDecoderCore { contentColorVolume = HeifPropertyParser.ParseContentColorVolume(boxBuffer); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) { // Keep the understood property index without retaining invalid ancillary metadata. } @@ -1594,7 +1594,7 @@ internal sealed class HeifDecoderCore : ImageDecoderCore { ambientViewingEnvironment = HeifPropertyParser.ParseAmbientViewingEnvironment(boxBuffer); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) { // Keep the understood property index without retaining invalid ancillary metadata. } @@ -1607,7 +1607,7 @@ internal sealed class HeifDecoderCore : ImageDecoderCore { referenceViewingEnvironment = HeifPropertyParser.ParseReferenceViewingEnvironment(boxBuffer); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) { // Keep the understood property index without retaining invalid ancillary metadata. } @@ -1620,7 +1620,7 @@ internal sealed class HeifDecoderCore : ImageDecoderCore { nominalDiffuseWhite = HeifPropertyParser.ParseNominalDiffuseWhite(boxBuffer); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(this.Options, ex)) { // Keep the understood property index without retaining invalid ancillary metadata. } @@ -1683,7 +1683,7 @@ internal sealed class HeifDecoderCore : ImageDecoderCore break; } } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreImageDataSegmentError(this.Options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreImageDataSegmentError(this.Options, ex)) { // Invalid image properties retain their physical association index. Typed association handling ignores // the placeholder so another decodable item or the coded-image defaults can remain usable. @@ -3153,4 +3153,42 @@ internal sealed class HeifDecoderCore : ImageDecoderCore bytesRead = terminator + 1; return Encoding.UTF8.GetString(span[..terminator]); } + + /// + /// Determines whether a malformed ancillary box can be omitted under the selected integrity policy. + /// + public static bool ShouldIgnoreAncillarySegmentError(DecoderOptions options, Exception exception) + => options.SegmentIntegrityHandling is not SegmentIntegrityHandling.Strict + && IsRecoverableBoxError(exception); + + /// + /// Determines whether a malformed image-data box can be omitted under the selected integrity policy. + /// + internal static bool ShouldIgnoreImageDataSegmentError(DecoderOptions options, Exception exception) + => options.SegmentIntegrityHandling is SegmentIntegrityHandling.IgnoreImageData + && IsRecoverableBoxError(exception); + + /// + /// Identifies malformed-box failures eligible for the segment integrity policy. + /// + /// The failure raised while reading the box. + /// Whether the failure describes recoverable image content. + private static bool IsRecoverableBoxError(Exception exception) + => exception is ImageFormatException + or InvalidIccProfileException + or InvalidImageContentException + or InvalidOperationException + or NotSupportedException; + + /// + /// Rejects malformed image properties unless image-data errors are explicitly ignored. + /// + /// The description of the malformed property. + private void ThrowOrIgnoreImageDataSegmentError(string message) + { + if (this.Options.SegmentIntegrityHandling is not SegmentIntegrityHandling.IgnoreImageData) + { + throw new InvalidImageContentException(message); + } + } } diff --git a/src/ImageSharp/Formats/Heif/HeifEncoderCore.Sequence.cs b/src/ImageSharp/Formats/Heif/HeifEncoderCore.Sequence.cs index 746a92900c..9e2f52b07e 100644 --- a/src/ImageSharp/Formats/Heif/HeifEncoderCore.Sequence.cs +++ b/src/ImageSharp/Formats/Heif/HeifEncoderCore.Sequence.cs @@ -339,7 +339,7 @@ internal sealed partial class HeifEncoderCore IccProfile? iccProfile = image.Metadata.IccProfile; if (!this.encoder.SkipMetadata && iccProfile is not null) { - iccProfileData = iccProfile.GetDataForWriting(); + iccProfileData = iccProfile.ToByteArray(); } return new HeifSequenceEncoding( diff --git a/src/ImageSharp/Formats/Heif/HeifItem.cs b/src/ImageSharp/Formats/Heif/HeifItem.cs index e1c1ec4c3a..b51fc53872 100644 --- a/src/ImageSharp/Formats/Heif/HeifItem.cs +++ b/src/ImageSharp/Formats/Heif/HeifItem.cs @@ -224,7 +224,7 @@ internal sealed class HeifItem(Heif4CharCode type, uint id) { // Exact-size container writing queries the payload length before copying it. Retaining the serialized // view on this transient item prevents an entry-built profile from being serialized for both passes. - this.serializedIccProfile = this.iccProfile.GetDataForWriting(); + this.serializedIccProfile = this.iccProfile.ToByteArray(); } return this.serializedIccProfile; diff --git a/src/ImageSharp/Formats/Heif/HeifSequenceParser.cs b/src/ImageSharp/Formats/Heif/HeifSequenceParser.cs index 6fff6edf2f..3006822a54 100644 --- a/src/ImageSharp/Formats/Heif/HeifSequenceParser.cs +++ b/src/ImageSharp/Formats/Heif/HeifSequenceParser.cs @@ -162,7 +162,7 @@ internal sealed class HeifSequenceParser { ValidateAlphaTrack(colorTrack, alphaTrack); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreImageDataSegmentError(this.options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreImageDataSegmentError(this.options, ex)) { // Alpha is optional image data. IgnoreImageData permits a malformed auxiliary sequence to be omitted while // retaining the independently decodable color presentation. @@ -304,7 +304,7 @@ internal sealed class HeifSequenceParser stream.Position = metadata.Offset; track.Metadata = this.metadataParser.Parse(stream, metadata.Length, scratch); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(this.options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(this.options, ex)) { // The validated parent range lets decoding continue safely without this optional metadata box. } @@ -963,7 +963,7 @@ internal sealed class HeifSequenceParser { ParseTrackImageProperty(stream, childLength, childType, track, scratch); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(this.options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(this.options, ex)) { // The complete child range remains known, so optional metadata can be discarded safely. } @@ -977,7 +977,7 @@ internal sealed class HeifSequenceParser { ParseTrackImageProperty(stream, childLength, childType, track, scratch); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreImageDataSegmentError(this.options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreImageDataSegmentError(this.options, ex)) { // IgnoreImageData permits a recoverable presentation property to be omitted. } @@ -1125,7 +1125,7 @@ internal sealed class HeifSequenceParser prefix = ReadPrefixFromStart(stream, boxLength, scratch, 11, "color information"); track.CicpProfile = HeifPropertyParser.ParseCicpProfile(prefix[4..]); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreImageDataSegmentError(this.options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreImageDataSegmentError(this.options, ex)) { // IgnoreImageData permits the decoder to fall back to the coded sequence's color description. } @@ -1150,7 +1150,7 @@ internal sealed class HeifSequenceParser HeifBoxReader.ReadExactly(stream, profileData, "Stream length is not sufficient for box content."); track.IccProfile = HeifPropertyParser.ParseIccProfile(profileData); } - catch (Exception ex) when (ImageDecoderCore.ShouldIgnoreAncillarySegmentError(this.options, ex)) + catch (Exception ex) when (HeifDecoderCore.ShouldIgnoreAncillarySegmentError(this.options, ex)) { // A malformed optional ICC profile does not invalidate the coded image outside strict mode. } diff --git a/src/ImageSharp/Formats/ImageDecoderCore.cs b/src/ImageSharp/Formats/ImageDecoderCore.cs index a5b238c58d..3f36b8931f 100644 --- a/src/ImageSharp/Formats/ImageDecoderCore.cs +++ b/src/ImageSharp/Formats/ImageDecoderCore.cs @@ -39,7 +39,7 @@ internal abstract class ImageDecoderCore /// The action. protected void ExecuteAncillarySegmentAction(Action action) { - if (!ShouldIgnoreAncillarySegmentErrors(this.Options)) + if (this.Options.SegmentIntegrityHandling is SegmentIntegrityHandling.Strict) { action(); return; @@ -49,7 +49,12 @@ internal abstract class ImageDecoderCore { action(); } - catch (Exception ex) when (IsRecoverableSegmentError(ex)) + catch (Exception ex) when (ex + is ImageFormatException + or InvalidIccProfileException + or InvalidImageContentException + or InvalidOperationException + or NotSupportedException) { // Intentionally ignored in non-strict segment integrity modes. } @@ -61,7 +66,7 @@ internal abstract class ImageDecoderCore /// The action. protected void ExecuteImageDataSegmentAction(Action action) { - if (!ShouldIgnoreImageDataSegmentErrors(this.Options)) + if (this.Options.SegmentIntegrityHandling is not SegmentIntegrityHandling.IgnoreImageData) { action(); return; @@ -71,62 +76,21 @@ internal abstract class ImageDecoderCore { action(); } - catch (Exception ex) when (IsRecoverableSegmentError(ex)) + catch (Exception ex) when (ex + is ImageFormatException + or InvalidIccProfileException + or InvalidImageContentException + or InvalidOperationException + or NotSupportedException) { // Intentionally ignored when image data integrity handling is set to IgnoreImageData. } } - /// - /// Determines whether an exception represents a recoverable image segment error. - /// - /// The exception raised while processing an image segment. - /// when a segment integrity policy may ignore the exception. - public static bool IsRecoverableSegmentError(Exception exception) - => exception is ImageFormatException - or InvalidIccProfileException - or InvalidImageContentException - or InvalidOperationException - or NotSupportedException; - - /// - /// Determines whether the configured policy permits recoverable ancillary-segment errors to be ignored. - /// - /// The general decoder options. - /// when recoverable ancillary-segment errors may be ignored. - public static bool ShouldIgnoreAncillarySegmentErrors(DecoderOptions options) - => options.SegmentIntegrityHandling is not SegmentIntegrityHandling.Strict; - - /// - /// Determines whether the configured policy permits recoverable image-data-segment errors to be ignored. - /// - /// The general decoder options. - /// when recoverable image-data-segment errors may be ignored. - public static bool ShouldIgnoreImageDataSegmentErrors(DecoderOptions options) - => options.SegmentIntegrityHandling is SegmentIntegrityHandling.IgnoreImageData; - - /// - /// Determines whether an ancillary-segment exception may be ignored by the configured decoder policy. - /// - /// The general decoder options. - /// The exception raised while processing an ancillary segment. - /// when decoding may continue without the ancillary segment. - public static bool ShouldIgnoreAncillarySegmentError(DecoderOptions options, Exception exception) - => ShouldIgnoreAncillarySegmentErrors(options) && IsRecoverableSegmentError(exception); - - /// - /// Determines whether an image-data-segment exception may be ignored by the configured decoder policy. - /// - /// The general decoder options. - /// The exception raised while processing an image-data segment. - /// when decoding may continue without the image-data segment. - public static bool ShouldIgnoreImageDataSegmentError(DecoderOptions options, Exception exception) - => ShouldIgnoreImageDataSegmentErrors(options) && IsRecoverableSegmentError(exception); - /// /// Throws unless the decoder is running in a non-strict segment integrity mode. - /// Use this when ancillary parsing must continue locally after the error rather than returning through - /// . + /// Use this only from within when local control flow + /// must continue after the error. /// /// The exception message. protected void ThrowOrIgnoreNonStrictSegmentError(string message) @@ -137,18 +101,6 @@ internal abstract class ImageDecoderCore } } - /// - /// Throws unless the decoder permits recoverable image-data segment errors to be ignored. - /// - /// The exception message. - protected void ThrowOrIgnoreImageDataSegmentError(string message) - { - if (!ShouldIgnoreImageDataSegmentErrors(this.Options)) - { - throw new InvalidImageContentException(message); - } - } - /// /// Reads the raw image information from the specified stream. /// diff --git a/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs b/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs index d337b77e14..eaba0a045c 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs @@ -177,22 +177,6 @@ public sealed partial class IccProfile : IDeepCloneable return IccWriter.Write(this); } - /// - /// Gets the serialized profile storage for an encoder that consumes it before the operation returns. - /// - /// The existing raw profile storage, or a newly serialized profile when this instance was built from entries. - internal ReadOnlyMemory GetDataForWriting() - { - if (this.data is not null) - { - // Internal encoders only read this memory during the current operation, so the immutable view avoids - // cloning an already-owned profile before it is copied into format-specific output. - return this.data; - } - - return IccWriter.Write(this); - } - private void InitializeHeader() { if (this.header != null) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index e5faf976cf..45c1311c9d 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -348,6 +348,7 @@ public partial class PixelOperations /// /// Bulk operation that packs 3 separate RGB channels to . + /// The destination must contain at least as many pixels as each source channel. /// /// A to the red values. /// A to the green values. diff --git a/src/ImageSharp/Primitives/Point.cs b/src/ImageSharp/Primitives/Point.cs index 8e9cadcbec..99193e3bb0 100644 --- a/src/ImageSharp/Primitives/Point.cs +++ b/src/ImageSharp/Primitives/Point.cs @@ -145,24 +145,6 @@ public struct Point : IEquatable public static Point operator /(Point left, int right) => new(left.X / right, left.Y / right); - /// - /// Shift to the right by a amount producing . - /// - /// Shifted value of type . - /// Shifted amount of type . - /// Result of type . - public static Point operator >>(Point left, int right) - => new(left.X >> right, left.Y >> right); - - /// - /// Shift to the left by a amount producing . - /// - /// Shifted value of type . - /// Shifted amount of type . - /// Result of type . - public static Point operator <<(Point left, int right) - => new(left.X << right, left.Y << right); - /// /// Compares two objects for equality. /// @@ -298,24 +280,6 @@ public struct Point : IEquatable [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Offset(Point point) => this.Offset(point.X, point.Y); - /// - /// Shifts the coordinate value of this to the right with the specified amount. - /// - /// The point to shift. - /// The number of bits to shift to the right. - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point ShiftRight(Point point, int bitCount) => new(unchecked(point.X >> bitCount), unchecked(point.Y >> bitCount)); - - /// - /// Shifts the coordinate value of this to the left with the specified amount. - /// - /// The point to shift. - /// The number of bits to shift to the left. - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point ShiftLeft(Point point, int bitCount) => new(unchecked(point.X << bitCount), unchecked(point.Y << bitCount)); - /// public override readonly int GetHashCode() => HashCode.Combine(this.X, this.Y); diff --git a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1IntraSuperblockEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1IntraSuperblockEncoderTests.cs index b6ab67d5ee..c5147d9680 100644 --- a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1IntraSuperblockEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1IntraSuperblockEncoderTests.cs @@ -670,7 +670,7 @@ public class Av1IntraSuperblockEncoderTests const int Width = 8; const int Height = 8; Point blockOrigin = new(isIntraBlockCopy ? 320 : 0, 0); - Point modeInfoPosition = blockOrigin >> Av1Constants.ModeInfoSizeLog2; + Point modeInfoPosition = new(blockOrigin.X >> Av1Constants.ModeInfoSizeLog2, blockOrigin.Y >> Av1Constants.ModeInfoSizeLog2); int frameWidth = blockOrigin.X + Width; int superblockIndex = blockOrigin.X / 64; ObuColorConfig colorConfig = new() diff --git a/tests/ImageSharp.Tests/Primitives/PointTests.cs b/tests/ImageSharp.Tests/Primitives/PointTests.cs index b740cbb28d..d2192f53bb 100644 --- a/tests/ImageSharp.Tests/Primitives/PointTests.cs +++ b/tests/ImageSharp.Tests/Primitives/PointTests.cs @@ -4,7 +4,7 @@ using System.Globalization; using System.Numerics; -namespace SixLabors.ImageSharp.Tests.Primitives; +namespace SixLabors.ImageSharp.Tests; public class PointTests { @@ -112,27 +112,6 @@ public class PointTests Assert.Equal(subExpected, Point.Subtract(p, s)); } - [Theory] - [InlineData(int.MaxValue, int.MaxValue, 5)] - [InlineData(int.MinValue, int.MinValue, 4)] - [InlineData(int.MaxValue, int.MaxValue, 2)] - [InlineData(0, 0, 3)] - public void ShiftTest(int x, int y, int s) - { - Point rightExpected, leftExpected, p = new Point(x, y); - - unchecked - { - rightExpected = new Point(x >> s, y >> s); - leftExpected = new Point(x << s, y << s); - } - - Assert.Equal(rightExpected, p >> s); - Assert.Equal(leftExpected, p << s); - Assert.Equal(rightExpected, Point.ShiftRight(p, s)); - Assert.Equal(leftExpected, Point.ShiftLeft(p, s)); - } - [Theory] [InlineData(float.MaxValue, float.MinValue)] [InlineData(float.MinValue, float.MinValue)]