private void PopulateItemInfos() { IReadOnlyList <AvifWriterItem> items = this.state.Items; ItemInfoBox itemInfoBox = this.metaBox.ItemInfo; for (int i = 0; i < items.Count; i++) { AvifWriterItem item = items[i]; if (item.ItemInfoEntry != null) { itemInfoBox.Add(item.ItemInfoEntry); } } }
private void PopulateItemReferences() { IReadOnlyList <AvifWriterItem> items = this.state.Items; ItemReferenceBox itemReferenceBox = this.metaBox.ItemReferences; for (int i = 0; i < items.Count; i++) { AvifWriterItem item = items[i]; if (item.ItemReferences.Count > 0) { itemReferenceBox.Add(item.ItemReferences); } } }
private void PopulateItemLocations() { IReadOnlyList <AvifWriterItem> items = this.state.Items; ItemLocationBox itemLocationBox = this.metaBox.ItemLocations; for (int i = 0; i < items.Count; i++) { AvifWriterItem item = items[i]; if (item.ItemLocation != null) { itemLocationBox.Add(item.ItemLocation); } } }
private void Initialize(IReadOnlyList <CompressedAV1Image> colorImages, IReadOnlyList <CompressedAV1Image> alphaImages, ImageGridMetadata imageGridMetadata, AvifMetadata metadata, IByteArrayPool arrayPool) { ImageStateInfo result; if (imageGridMetadata != null) { result = InitializeFromImageGrid(colorImages, alphaImages, imageGridMetadata); this.ItemDataBox = CreateItemDataBox(imageGridMetadata, arrayPool); } else { result = InitializeFromSingleImage(colorImages[0], alphaImages?[0]); this.ItemDataBox = null; } uint itemId = result.NextId; ulong mediaDataBoxContentSize = result.MediaDataBoxContentSize; byte[] exif = metadata.GetExifBytesReadOnly(); if (exif != null && exif.Length > 0) { AvifWriterItem exifItem = AvifWriterItem.CreateFromExif(itemId, exif); itemId++; exifItem.ItemReferences.Add(new ItemReferenceEntryBox(exifItem.Id, ReferenceTypes.ContentDescription, this.PrimaryItemId)); this.items.Add(exifItem); mediaDataBoxContentSize += (ulong)exifItem.ContentBytes.Length; } byte[] xmp = metadata.GetXmpBytesReadOnly(); if (xmp != null && xmp.Length > 0) { AvifWriterItem xmpItem = AvifWriterItem.CreateFromXmp(itemId, xmp); xmpItem.ItemReferences.Add(new ItemReferenceEntryBox(xmpItem.Id, ReferenceTypes.ContentDescription, this.PrimaryItemId)); this.items.Add(xmpItem); mediaDataBoxContentSize += (ulong)xmpItem.ContentBytes.Length; } this.MediaDataBoxContentSize = mediaDataBoxContentSize; }
public void WriteTo(Stream stream) { using (BigEndianBinaryWriter writer = new BigEndianBinaryWriter(stream, true, this.arrayPool)) { this.fileTypeBox.Write(writer); this.metaBox.Write(writer); new MediaDataBox(this.state.MediaDataBoxContentSize).Write(writer); IReadOnlyList <AvifWriterItem> items = this.state.Items; for (int i = 0; i < items.Count; i++) { AvifWriterItem item = items[i]; if (item.Image is null && item.ContentBytes is null) { continue; } // We only ever write items with a single extent. item.ItemLocation.Extents[0].WriteFinalOffset(writer, (ulong)writer.Position); if (item.Image != null) { item.Image.Data.Write(writer); this.progressDone++; this.progressCallback?.Invoke(this, new ProgressEventArgs(((double)this.progressDone / this.progressTotal) * 100.0)); } else { writer.Write(item.ContentBytes); } } } }
private ImageStateInfo InitializeFromSingleImage(CompressedAV1Image color, CompressedAV1Image alpha) { ulong mediaDataBoxContentSize = color.Data.ByteLength; uint itemId = FirstItemId; AvifWriterItem colorItem = AvifWriterItem.CreateFromImage(itemId, "Color", color, false); itemId++; this.PrimaryItemId = colorItem.Id; this.items.Add(colorItem); if (alpha != null) { AvifWriterItem alphaItem = AvifWriterItem.CreateFromImage(itemId, "Alpha", alpha, true); itemId++; alphaItem.ItemReferences.Add(new ItemReferenceEntryBox(alphaItem.Id, ReferenceTypes.AuxiliaryImage, this.PrimaryItemId)); this.AlphaItemId = alphaItem.Id; this.items.Add(alphaItem); mediaDataBoxContentSize += alpha.Data.ByteLength; } return(new ImageStateInfo(mediaDataBoxContentSize, itemId)); }
private void PopulateItemProperties() { IReadOnlyList <AvifWriterItem> items = this.state.Items; ItemPropertiesBox itemPropertiesBox = this.metaBox.ItemProperties; // The property association ids are 1-based ushort propertyAssociationIndex = 1; // Cache the property association index values for the ImageSpatialExtentsBox // and PixelAspectRatioBox. // These boxes can be shared between the color and alpha images, which provides // a small reduction in file size. // // Gray-scale images can also share the AV1ConfigBox and PixelInformationBox // between the color and alpha images. // This works because the color and alpha images are the same size and YUV format. ushort imageSpatialExtentsAssociationIndex = 0; ushort pixelAspectRatioAssociationIndex = 0; ushort colorAv1ConfigAssociationIndex = 0; ushort colorPixelInformationAssociationIndex = 0; ushort alphaAv1ConfigAssociationIndex = 0; ushort alphaPixelInformationAssociationIndex = 0; ushort alphaChannelAssociationIndex = 0; for (int i = 0; i < items.Count; i++) { AvifWriterItem item = items[i]; if (item.Image != null) { if (imageSpatialExtentsAssociationIndex == 0) { itemPropertiesBox.AddProperty(new ImageSpatialExtentsBox((uint)item.Image.Width, (uint)item.Image.Height)); imageSpatialExtentsAssociationIndex = propertyAssociationIndex; propertyAssociationIndex++; } itemPropertiesBox.AddPropertyAssociation(item.Id, false, imageSpatialExtentsAssociationIndex); if (pixelAspectRatioAssociationIndex == 0) { itemPropertiesBox.AddProperty(new PixelAspectRatioBox(1, 1)); pixelAspectRatioAssociationIndex = propertyAssociationIndex; propertyAssociationIndex++; } itemPropertiesBox.AddPropertyAssociation(item.Id, false, pixelAspectRatioAssociationIndex); if (colorAv1ConfigAssociationIndex == 0 || item.IsAlphaImage && alphaAv1ConfigAssociationIndex == 0) { itemPropertiesBox.AddProperty(AV1ConfigBoxBuilder.Build(item.Image)); if (this.colorImageIsGrayscale) { colorAv1ConfigAssociationIndex = alphaAv1ConfigAssociationIndex = propertyAssociationIndex; } else { if (item.IsAlphaImage) { alphaAv1ConfigAssociationIndex = propertyAssociationIndex; } else { colorAv1ConfigAssociationIndex = propertyAssociationIndex; } } propertyAssociationIndex++; } if (colorPixelInformationAssociationIndex == 0 || item.IsAlphaImage && alphaPixelInformationAssociationIndex == 0) { itemPropertiesBox.AddProperty(new PixelInformationBox(item.Image.Format)); if (this.colorImageIsGrayscale) { colorPixelInformationAssociationIndex = alphaPixelInformationAssociationIndex = propertyAssociationIndex; } else { if (item.IsAlphaImage) { alphaPixelInformationAssociationIndex = propertyAssociationIndex; } else { colorPixelInformationAssociationIndex = propertyAssociationIndex; } } propertyAssociationIndex++; } if (item.IsAlphaImage) { itemPropertiesBox.AddPropertyAssociation(item.Id, true, alphaAv1ConfigAssociationIndex); itemPropertiesBox.AddPropertyAssociation(item.Id, true, alphaPixelInformationAssociationIndex); if (alphaChannelAssociationIndex == 0) { itemPropertiesBox.AddProperty(new AlphaChannelBox()); alphaChannelAssociationIndex = propertyAssociationIndex; propertyAssociationIndex++; } itemPropertiesBox.AddPropertyAssociation(item.Id, true, alphaChannelAssociationIndex); } else { itemPropertiesBox.AddPropertyAssociation(item.Id, true, colorAv1ConfigAssociationIndex); itemPropertiesBox.AddPropertyAssociation(item.Id, true, colorPixelInformationAssociationIndex); } } } if (this.state.ImageGrid != null) { itemPropertiesBox.AddProperty(new ImageSpatialExtentsBox(this.state.ImageGrid.OutputWidth, this.state.ImageGrid.OutputHeight)); ushort gridImageSpatialExtentsAssociationIndex = propertyAssociationIndex; propertyAssociationIndex++; itemPropertiesBox.AddPropertyAssociation(this.state.PrimaryItemId, false, gridImageSpatialExtentsAssociationIndex); if (this.state.AlphaItemId != 0) { itemPropertiesBox.AddPropertyAssociation(this.state.AlphaItemId, false, gridImageSpatialExtentsAssociationIndex); itemPropertiesBox.AddPropertyAssociation(this.state.AlphaItemId, true, alphaChannelAssociationIndex); } } if (this.colorInformationBox != null) { itemPropertiesBox.AddProperty(this.colorInformationBox); itemPropertiesBox.AddPropertyAssociation(this.state.PrimaryItemId, true, propertyAssociationIndex); } }
private ImageStateInfo InitializeFromImageGrid(IReadOnlyList <CompressedAV1Image> colorImages, IReadOnlyList <CompressedAV1Image> alphaImages, ImageGridMetadata imageGridMetadata) { ulong mediaDataBoxContentSize = 0; uint itemId = FirstItemId; List <uint> colorImageIds = new List <uint>(colorImages.Count); List <uint> alphaImageIds = alphaImages != null ? new List <uint>(alphaImages.Count) : null; for (int i = 0; i < colorImages.Count; i++) { CompressedAV1Image color = colorImages[i]; AvifWriterItem colorItem = AvifWriterItem.CreateFromImage(itemId, null, color, false); itemId++; colorImageIds.Add(colorItem.Id); this.items.Add(colorItem); mediaDataBoxContentSize += color.Data.ByteLength; if (alphaImages != null) { CompressedAV1Image alpha = alphaImages[i]; AvifWriterItem alphaItem = AvifWriterItem.CreateFromImage(itemId, null, alpha, true); itemId++; alphaItem.ItemReferences.Add(new ItemReferenceEntryBox(alphaItem.Id, ReferenceTypes.AuxiliaryImage, colorItem.Id)); alphaImageIds.Add(alphaItem.Id); this.items.Add(alphaItem); mediaDataBoxContentSize += alpha.Data.ByteLength; } } ulong gridDescriptorLength; if (imageGridMetadata.OutputHeight > ushort.MaxValue || imageGridMetadata.OutputWidth > ushort.MaxValue) { gridDescriptorLength = ImageGridDescriptor.LargeDescriptorLength; } else { gridDescriptorLength = ImageGridDescriptor.SmallDescriptorLength; } AvifWriterItem colorGridItem = AvifWriterItem.CreateFromImageGrid(itemId, "Color", 0, gridDescriptorLength); itemId++; colorGridItem.ItemReferences.Add(new ItemReferenceEntryBox(colorGridItem.Id, ReferenceTypes.DerivedImage, colorImageIds)); this.PrimaryItemId = colorGridItem.Id; this.items.Add(colorGridItem); if (alphaImages != null) { // The ImageGridDescriptor is shared between the color and alpha image. AvifWriterItem alphaGridItem = AvifWriterItem.CreateFromImageGrid(itemId, "Alpha", 0, gridDescriptorLength); itemId++; alphaGridItem.ItemReferences.Add(new ItemReferenceEntryBox(alphaGridItem.Id, ReferenceTypes.AuxiliaryImage, colorGridItem.Id)); alphaGridItem.ItemReferences.Add(new ItemReferenceEntryBox(alphaGridItem.Id, ReferenceTypes.DerivedImage, alphaImageIds)); this.AlphaItemId = alphaGridItem.Id; this.items.Add(alphaGridItem); } return(new ImageStateInfo(mediaDataBoxContentSize, itemId)); }