public AvifWriterState(IReadOnlyList <CompressedAV1Image> colorImages,
                                   IReadOnlyList <CompressedAV1Image> alphaImages,
                                   ImageGridMetadata imageGridMetadata,
                                   AvifMetadata metadata,
                                   IByteArrayPool arrayPool)
            {
                if (colorImages is null)
                {
                    ExceptionUtil.ThrowArgumentNullException(nameof(colorImages));
                }

                if (metadata is null)
                {
                    ExceptionUtil.ThrowArgumentNullException(nameof(metadata));
                }

                if (arrayPool is null)
                {
                    ExceptionUtil.ThrowArgumentNullException(nameof(arrayPool));
                }

                this.ImageGrid = imageGridMetadata;
                this.items     = new List <AvifWriterItem>(GetItemCount(colorImages, alphaImages, metadata));
                Initialize(colorImages, alphaImages, imageGridMetadata, metadata, arrayPool);
            }
Exemplo n.º 2
0
        /// <summary>
        /// Reads the specified number of bytes from the stream, starting from a specified point in the byte array.
        /// </summary>
        /// <param name="bytes">The bytes.</param>
        /// <param name="offset">The starting offset in the array.</param>
        /// <param name="count">The count.</param>
        /// <exception cref="ArgumentNullException"><paramref name="bytes"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> is negative.</exception>
        /// <exception cref="EndOfStreamException">The end of the stream has been reached.</exception>
        /// <exception cref="ObjectDisposedException">The object has been disposed.</exception>
        public unsafe void ProperRead(byte[] bytes, int offset, int count)
        {
            if (bytes is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(bytes));
            }
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }
            VerifyNotDisposed();

            if (count == 0)
            {
                return;
            }

            int totalBytesRead = 0;

            while (totalBytesRead < count)
            {
                int bytesRead = ReadInternal(bytes, offset + totalBytesRead, count - totalBytesRead);

                if (bytesRead == 0)
                {
                    throw new EndOfStreamException();
                }

                totalBytesRead += bytesRead;
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="AvifReader"/> class.
        /// </summary>
        /// <param name="parser">The parser.</param>
        /// <exception cref="ArgumentNullException"><paramref name="input"/> is null.</exception>
        public AvifReader(Stream input, bool leaveOpen, IByteArrayPool arrayPool)
        {
            if (input is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(input));
            }

            // The parser is initialized first because it will throw an exception
            // if the AVIF file is invalid or not supported.
            this.parser        = new AvifParser(input, leaveOpen, arrayPool);
            this.primaryItemId = this.parser.GetPrimaryItemId();
            this.alphaItemId   = this.parser.GetAlphaItemId(this.primaryItemId);
            this.colorInfoBox  = this.parser.TryGetColorInfoBox(this.primaryItemId);
            this.parser.GetTransformationProperties(this.primaryItemId,
                                                    out this.cleanApertureBox,
                                                    out this.imageRotateBox,
                                                    out this.imageMirrorBox);
            this.colorGridInfo = this.parser.TryGetImageGridInfo(this.primaryItemId);
            if (this.alphaItemId != 0)
            {
                this.alphaGridInfo = this.parser.TryGetImageGridInfo(this.alphaItemId);
            }
            else
            {
                this.alphaGridInfo = null;
            }
        }
Exemplo n.º 4
0
        public static void DecompressAlpha(AvifItemData alphaImage,
                                           DecodeInfo decodeInfo,
                                           Surface fullSurface)
        {
            if (alphaImage is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(alphaImage));
            }

            if (decodeInfo is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(decodeInfo));
            }

            if (fullSurface is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(fullSurface));
            }

            DecoderStatus status = DecoderStatus.Ok;

            unsafe
            {
                alphaImage.UseBufferPointer((ptr, length) =>
                {
                    BitmapData bitmapData = new BitmapData
                    {
                        scan0  = fullSurface.Scan0.Pointer,
                        width  = (uint)fullSurface.Width,
                        height = (uint)fullSurface.Height,
                        stride = (uint)fullSurface.Stride
                    };

                    UIntPtr alphaImageSize = new UIntPtr(length);

                    if (IntPtr.Size == 8)
                    {
                        status = AvifNative_64.DecompressAlphaImage(ptr,
                                                                    alphaImageSize,
                                                                    decodeInfo,
                                                                    ref bitmapData);
                    }
                    else
                    {
                        status = AvifNative_86.DecompressAlphaImage(ptr,
                                                                    alphaImageSize,
                                                                    decodeInfo,
                                                                    ref bitmapData);
                    }
                });
            }

            if (status != DecoderStatus.Ok)
            {
                HandleError(status);
            }
        }
Exemplo n.º 5
0
        public void Write(byte[] bytes)
        {
            if (bytes is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(bytes));
            }

            Write(bytes, 0, bytes.Length);
        }
Exemplo n.º 6
0
        public unsafe void Write(SafeBuffer buffer)
        {
            if (buffer is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(buffer));
            }

            VerifyNotDisposed();

            ulong length = buffer.ByteLength;

            if (length == 0)
            {
                return;
            }

            // The largest multiple of 4096 that is under the large object heap limit.
            const int MaxBufferSize = 81920;

            int bufferSize = (int)Math.Min(length, MaxBufferSize);

            byte[] writeBuffer = this.arrayPool.Rent(bufferSize);

            byte *readPtr = null;

            System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                buffer.AcquirePointer(ref readPtr);

                fixed(byte *writePtr = writeBuffer)
                {
                    ulong totalBytesRead = 0;

                    while (totalBytesRead < length)
                    {
                        ulong bytesRead = Math.Min(length - totalBytesRead, MaxBufferSize);

                        Buffer.MemoryCopy(readPtr + totalBytesRead, writePtr, bytesRead, bytesRead);

                        this.stream.Write(writeBuffer, 0, (int)bytesRead);

                        totalBytesRead += bytesRead;
                    }
                }
            }
            finally
            {
                if (readPtr != null)
                {
                    buffer.ReleasePointer();
                }
            }

            this.arrayPool.Return(writeBuffer);
        }
#pragma warning restore IDE0032 // Use auto property

        public EndianBinaryReaderSegment(EndianBinaryReader reader, long startOffset, long length)
        {
            if (reader is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(reader));
            }

            this.reader      = reader;
            this.startOffset = startOffset;
            this.endOffset   = checked (startOffset + length);
        }
Exemplo n.º 8
0
        public unsafe void UseBufferPointer(UseBufferPointerDelegate action)
        {
            if (action is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(action));
            }

            VerifyNotDisposed();

            UseBufferPointerImpl(action);
        }
Exemplo n.º 9
0
        /// <summary>
        /// Reads the specified number of bytes from the stream, starting from a specified point in the SafeBuffer.
        /// </summary>
        /// <param name="buffer">The buffer.</param>
        /// <param name="offset">The starting offset in the buffer.</param>
        /// <param name="count">The count.</param>
        /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is null.</exception>
        /// <exception cref="EndOfStreamException">The end of the stream has been reached.</exception>
        /// <exception cref="ObjectDisposedException">The object has been disposed.</exception>
        public unsafe void ProperRead(SafeBuffer buffer, ulong offset, ulong count)
        {
            if (buffer is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(buffer));
            }
            VerifyNotDisposed();

            if (count == 0)
            {
                return;
            }

            // The largest multiple of 4096 that is under the large object heap limit.
            const int MaxReadBufferSize = 81920;

            byte[] readBuffer = this.arrayPool.Rent((int)Math.Min(count, MaxReadBufferSize));

            byte *writePtr = null;

            System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                buffer.AcquirePointer(ref writePtr);

                fixed(byte *readPtr = readBuffer)
                {
                    ulong totalBytesRead = 0;

                    while (totalBytesRead < count)
                    {
                        ulong bytesRead = (ulong)ReadInternal(readBuffer, 0, (int)Math.Min(count - totalBytesRead, MaxReadBufferSize));

                        if (bytesRead == 0)
                        {
                            throw new EndOfStreamException();
                        }

                        Buffer.MemoryCopy(readPtr, writePtr + offset + totalBytesRead, bytesRead, bytesRead);

                        totalBytesRead += bytesRead;
                    }
                }
            }
            finally
            {
                if (writePtr != null)
                {
                    buffer.ReleasePointer();
                }
            }

            this.arrayPool.Return(readBuffer);
        }
Exemplo n.º 10
0
        public BigEndianBinaryWriter(Stream stream, bool leaveOpen, IByteArrayPool arrayPool)
        {
            if (stream is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(stream));
            }

            this.stream    = stream;
            this.leaveOpen = leaveOpen;
            this.buffer    = new byte[sizeof(ulong)];
            this.arrayPool = arrayPool;
        }
Exemplo n.º 11
0
        public AvifParser(Stream stream, bool leaveOpen, IByteArrayPool arrayPool)
        {
            if (stream is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(stream));
            }

            this.arrayPool = arrayPool;
            this.reader    = new EndianBinaryReader(stream, Endianess.Big, leaveOpen, arrayPool);
            Parse();
            this.fileLength = (ulong)stream.Length;
        }
Exemplo n.º 12
0
        public AvifItemData ReadItemData(ItemLocationEntry entry)
        {
            if (entry is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(entry));
            }

            AvifItemData data;

            if (entry.Extents.Count == 1)
            {
                long offset = CalculateExtentOffset(entry.BaseOffset, entry.ConstructionMethod, entry.Extents[0]);

                this.reader.Position = offset;

                ulong totalItemSize = entry.TotalItemSize;

                if (totalItemSize <= ManagedAvifItemDataMaxSize)
                {
                    ManagedAvifItemData managedItemData = new ManagedAvifItemData((int)totalItemSize, this.arrayPool);

                    this.reader.ProperRead(managedItemData.GetBuffer(), 0, (int)managedItemData.Length);

                    data = managedItemData;
                }
                else
                {
                    UnmanagedAvifItemData unmanagedItemData = new UnmanagedAvifItemData(totalItemSize);

                    try
                    {
                        this.reader.ProperRead(unmanagedItemData.UnmanagedBuffer, 0, totalItemSize);

                        data = unmanagedItemData;
                        unmanagedItemData = null;
                    }
                    finally
                    {
                        unmanagedItemData?.Dispose();
                    }
                }
            }
            else
            {
                data = ReadDataFromMultipleExtents(entry);
            }

            return(data);
        }
            private AvifWriterItem(uint id, string name, ulong dataBoxOffset, ulong length)
            {
                if (name is null)
                {
                    ExceptionUtil.ThrowArgumentNullException(nameof(name));
                }

                this.Id             = id;
                this.Name           = name;
                this.Image          = null;
                this.IsAlphaImage   = false;
                this.ContentBytes   = null;
                this.ItemInfoEntry  = new ImageGridItemInfoEntryBox(id, name);
                this.ItemLocation   = new ItemLocationEntry(id, dataBoxOffset, length);
                this.ItemReferences = new List <ItemReferenceEntryBox>();
            }
            private AvifWriterItem(uint id, string name, CompressedAV1Image image, bool isAlphaImage)
            {
                if (image is null)
                {
                    ExceptionUtil.ThrowArgumentNullException(nameof(image));
                }

                this.Id             = id;
                this.Name           = name;
                this.Image          = image;
                this.IsAlphaImage   = isAlphaImage;
                this.ContentBytes   = null;
                this.ItemInfoEntry  = new AV01ItemInfoEntryBox(id, name);
                this.ItemLocation   = new ItemLocationEntry(id, image.Data.ByteLength);
                this.ItemReferences = new List <ItemReferenceEntryBox>();
            }
Exemplo n.º 15
0
        internal static void Crop(CleanApertureBox cleanApertureBox, ref Surface surface)
        {
            if (cleanApertureBox is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(cleanApertureBox));
            }

            if (cleanApertureBox.Width.Denominator == 0 ||
                cleanApertureBox.Height.Denominator == 0 ||
                cleanApertureBox.HorizontalOffset.Denominator == 0 ||
                cleanApertureBox.VerticalOffset.Denominator == 0)
            {
                return;
            }

            int cropWidth  = cleanApertureBox.Width.ToInt32();
            int cropHeight = cleanApertureBox.Height.ToInt32();

            double offsetX = cleanApertureBox.HorizontalOffset.ToDouble();
            double offsetY = cleanApertureBox.VerticalOffset.ToDouble();

            double pictureCenterX = offsetX + ((surface.Width - 1) / 2.0);
            double pictureCenterY = offsetY + ((surface.Height - 1) / 2.0);

            int cropRectX = (int)Math.Round(pictureCenterX - ((cropWidth - 1) / 2.0));
            int cropRectY = (int)Math.Round(pictureCenterY - ((cropHeight - 1) / 2.0));

            Rectangle cropRect = new Rectangle(cropRectX, cropRectY, cropWidth, cropHeight);

            // Check that the crop rectangle is within the surface bounds.
            if (cropRect.IntersectsWith(surface.Bounds))
            {
                Surface temp = new Surface(cropWidth, cropHeight);
                try
                {
                    temp.CopySurface(surface, cropRect);

                    surface.Dispose();
                    surface = temp;
                    temp    = null;
                }
                finally
                {
                    temp?.Dispose();
                }
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// Initializes a new instance of the <see cref="EndianBinaryReader"/> class.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="byteOrder">The byte order of the stream.</param>
        /// <param name="leaveOpen">
        /// <see langword="true"/> to leave the stream open after the EndianBinaryReader is disposed; otherwise, <see langword="false"/>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="stream"/> is null.
        ///
        /// -or-
        ///
        /// <paramref name="arrayPool"/> is null.
        /// </exception>
        public EndianBinaryReader(Stream stream, Endianess byteOrder, bool leaveOpen, IByteArrayPool arrayPool)
        {
            if (arrayPool is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(arrayPool));
            }

            this.stream     = stream ?? throw new ArgumentNullException(nameof(stream));
            this.bufferSize = (int)Math.Min(stream.Length, MaxBufferSize);
            this.buffer     = arrayPool.Rent(this.bufferSize);
            this.endianess  = byteOrder;
            this.leaveOpen  = leaveOpen;
            this.arrayPool  = arrayPool;

            this.readOffset = 0;
            this.readLength = 0;
            this.disposed   = false;
        }
            private AvifWriterItem(uint id, string name, byte[] contentBytes, ItemInfoEntryBox itemInfo)
            {
                if (contentBytes is null)
                {
                    ExceptionUtil.ThrowArgumentNullException(nameof(contentBytes));
                }


                if (itemInfo is null)
                {
                    ExceptionUtil.ThrowArgumentNullException(nameof(itemInfo));
                }

                this.Id             = id;
                this.Name           = name;
                this.Image          = null;
                this.IsAlphaImage   = false;
                this.ContentBytes   = contentBytes;
                this.ItemInfoEntry  = itemInfo;
                this.ItemLocation   = new ItemLocationEntry(id, (ulong)contentBytes.Length);
                this.ItemReferences = new List <ItemReferenceEntryBox>();
            }
Exemplo n.º 18
0
        public static void DecompressColor(AvifItemData colorImage,
                                           CICPColorData?colorConversionInfo,
                                           DecodeInfo decodeInfo,
                                           Surface fullSurface)
        {
            if (colorImage is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(colorImage));
            }

            if (decodeInfo is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(decodeInfo));
            }

            if (fullSurface is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(fullSurface));
            }


            DecoderStatus status = DecoderStatus.Ok;

            unsafe
            {
                colorImage.UseBufferPointer((ptr, length) =>
                {
                    BitmapData bitmapData = new BitmapData
                    {
                        scan0  = fullSurface.Scan0.Pointer,
                        width  = (uint)fullSurface.Width,
                        height = (uint)fullSurface.Height,
                        stride = (uint)fullSurface.Stride
                    };
                    UIntPtr colorImageSize = new UIntPtr(length);

                    if (colorConversionInfo.HasValue)
                    {
                        CICPColorData colorData = colorConversionInfo.Value;

                        if (IntPtr.Size == 8)
                        {
                            status = AvifNative_64.DecompressColorImage(ptr,
                                                                        colorImageSize,
                                                                        ref colorData,
                                                                        decodeInfo,
                                                                        ref bitmapData);
                        }
                        else
                        {
                            status = AvifNative_86.DecompressColorImage(ptr,
                                                                        colorImageSize,
                                                                        ref colorData,
                                                                        decodeInfo,
                                                                        ref bitmapData);
                        }
                    }
                    else
                    {
                        if (IntPtr.Size == 8)
                        {
                            status = AvifNative_64.DecompressColorImage(ptr,
                                                                        colorImageSize,
                                                                        IntPtr.Zero,
                                                                        decodeInfo,
                                                                        ref bitmapData);
                        }
                        else
                        {
                            status = AvifNative_86.DecompressColorImage(ptr,
                                                                        colorImageSize,
                                                                        IntPtr.Zero,
                                                                        decodeInfo,
                                                                        ref bitmapData);
                        }
                    }
                });
            }

            if (status != DecoderStatus.Ok)
            {
                HandleError(status);
            }
        }
Exemplo n.º 19
0
        private long CalculateExtentOffset(ulong baseOffset, ConstructionMethod constructionMethod, ItemLocationExtent extent)
        {
            if (extent is null)
            {
                ExceptionUtil.ThrowArgumentNullException(nameof(extent));
            }

            ulong offset;

            try
            {
                if (constructionMethod == ConstructionMethod.FileOffset)
                {
                    checked
                    {
                        offset = baseOffset + extent.Offset;

                        if ((offset + extent.Length) > this.fileLength)
                        {
                            throw new FormatException("The item has an invalid file offset.");
                        }
                    }
                }
                else if (constructionMethod == ConstructionMethod.IDatBoxOffset)
                {
                    ItemDataBox dataBox = this.metaBox.ItemData;

                    if (dataBox is null)
                    {
                        throw new FormatException("The file does not have an item data box.");
                    }

                    checked
                    {
                        if ((extent.Offset + extent.Length) > (ulong)dataBox.Length)
                        {
                            throw new FormatException("The item has an invalid data box offset.");
                        }

                        offset = (ulong)dataBox.Offset + extent.Offset;

                        if ((offset + extent.Length) > this.fileLength)
                        {
                            throw new FormatException("The item has an invalid file offset.");
                        }
                    }
                }
                else
                {
                    throw new FormatException($"ItemLocationEntry construction method { constructionMethod } is not supported.");
                }
            }
            catch (OverflowException ex)
            {
                throw new FormatException("Overflow when attempting to calculate the item file offset.", ex);
            }

            if (offset > long.MaxValue)
            {
                throw new FormatException($"The item file offset exceeds {long.MaxValue:F0} bytes.");
            }

            return((long)offset);
        }