private void DecodeColorImage(uint itemId, DecodeInfo decodeInfo, CICPColorData?colorConversionInfo, Surface fullSurface) { using (AvifItemData color = ReadColorImage(itemId)) { AvifNative.DecompressColor(color, colorConversionInfo, decodeInfo, fullSurface); } }
private void DecodeAlphaImage(uint itemId, DecodeInfo decodeInfo, Surface fullSurface) { using (AvifItemData alpha = ReadAlphaImage(itemId)) { AvifNative.DecompressAlpha(alpha, decodeInfo, fullSurface); } }
public static void Save(Document document, Stream output, int quality, CompressionSpeed compressionSpeed, YUVChromaSubsampling chromaSubsampling, bool preserveExistingTileSize, int?maxEncoderThreadsOverride, Surface scratchSurface, ProgressEventHandler progressCallback, IByteArrayPool arrayPool) { using (RenderArgs args = new RenderArgs(scratchSurface)) { document.Render(args, true); } bool grayscale = IsGrayscaleImage(scratchSurface); AvifMetadata metadata = CreateAvifMetadata(document); EncoderOptions options = new EncoderOptions { quality = quality, compressionSpeed = compressionSpeed, // YUV 4:0:0 is always used for gray-scale images because it // produces the smallest file size with no quality loss. yuvFormat = grayscale ? YUVChromaSubsampling.Subsampling400 : chromaSubsampling, maxThreads = maxEncoderThreadsOverride ?? Environment.ProcessorCount }; // Use BT.709 with sRGB transfer characteristics as the default. CICPColorData colorConversionInfo = new CICPColorData { colorPrimaries = CICPColorPrimaries.BT709, transferCharacteristics = CICPTransferCharacteristics.Srgb, matrixCoefficients = CICPMatrixCoefficients.BT709, fullRange = true }; if (quality == 100 && !grayscale) { // The Identity matrix coefficient places the RGB values into the YUV planes without any conversion. // This reduces the compression efficiency, but allows for fully lossless encoding. options.yuvFormat = YUVChromaSubsampling.IdentityMatrix; // These CICP color values are from the AV1 Bitstream & Decoding Process Specification. colorConversionInfo = new CICPColorData { colorPrimaries = CICPColorPrimaries.BT709, transferCharacteristics = CICPTransferCharacteristics.Srgb, matrixCoefficients = CICPMatrixCoefficients.Identity, fullRange = true }; } else { Metadata docMetadata = document.Metadata; // Look for NCLX meta-data if the CICP meta-data was not found. // This preserves backwards compatibility with PDN files created by // previous versions of this plugin. string serializedData = docMetadata.GetUserValue(CICPMetadataName) ?? docMetadata.GetUserValue(NclxMetadataName); if (serializedData != null) { CICPColorData?colorData = CICPSerializer.TryDeserialize(serializedData); if (colorData.HasValue) { colorConversionInfo = colorData.Value; } } } ImageGridMetadata imageGridMetadata = TryGetImageGridMetadata(document, options.compressionSpeed, options.yuvFormat, preserveExistingTileSize); bool hasTransparency = HasTransparency(scratchSurface); CompressedAV1ImageCollection colorImages = new CompressedAV1ImageCollection(imageGridMetadata?.TileCount ?? 1); CompressedAV1ImageCollection alphaImages = hasTransparency ? new CompressedAV1ImageCollection(colorImages.Capacity) : null; // Progress is reported at the following stages: // 1. Before converting the image to the YUV color space // 2. Before compressing the color image // 3. After compressing the color image // 4. After compressing the alpha image (if present) // 5. After writing the color image to the file // 6. After writing the alpha image to the file (if present) uint progressDone = 0; uint progressTotal = hasTransparency ? 6U : 4U; if (colorImages.Capacity > 1) { progressTotal *= (uint)colorImages.Capacity; } try { Rectangle[] windowRectangles = GetTileWindowRectangles(imageGridMetadata, document); for (int i = 0; i < colorImages.Capacity; i++) { CompressedAV1Image color = null; CompressedAV1Image alpha = null; try { Rectangle windowRect = windowRectangles[i]; using (Surface window = scratchSurface.CreateWindow(windowRect)) { if (hasTransparency) { AvifNative.CompressWithTransparency(window, options, ReportCompressionProgress, ref progressDone, progressTotal, colorConversionInfo, out color, out alpha); } else { AvifNative.CompressWithoutTransparency(window, options, ReportCompressionProgress, ref progressDone, progressTotal, colorConversionInfo, out color); } } colorImages.Add(color); color = null; if (hasTransparency) { alphaImages.Add(alpha); alpha = null; } } finally { color?.Dispose(); alpha?.Dispose(); } } ColorInformationBox colorInformationBox; byte[] iccProfileBytes = metadata.GetICCProfileBytesReadOnly(); if (iccProfileBytes != null && iccProfileBytes.Length > 0) { colorInformationBox = new IccProfileColorInformation(iccProfileBytes); } else { colorInformationBox = new NclxColorInformation(colorConversionInfo.colorPrimaries, colorConversionInfo.transferCharacteristics, colorConversionInfo.matrixCoefficients, colorConversionInfo.fullRange); } AvifWriter writer = new AvifWriter(colorImages, alphaImages, metadata, imageGridMetadata, options.yuvFormat, colorInformationBox, progressCallback, progressDone, progressTotal, arrayPool); writer.WriteTo(output); } finally { colorImages?.Dispose(); alphaImages?.Dispose(); } bool ReportCompressionProgress(uint done, uint total) { try { progressCallback?.Invoke(null, new ProgressEventArgs(((double)done / total) * 100.0, true)); return(true); } catch (OperationCanceledException) { return(false); } } }