private static ProcessImageResult processImage(PipelineContext ctx, Stream ostm) { var frame = (WicImageFrame)ctx.ImageContainer.GetFrame(ctx.Settings.FrameIndex); ctx.AddFrameDisposer(); ctx.ImageFrame = frame; ctx.Source = frame.Source; MagicTransforms.AddGifFrameBuffer(ctx); ctx.FinalizeSettings(); WicTransforms.AddColorProfileReader(ctx); WicTransforms.AddNativeScaler(ctx); WicTransforms.AddExifFlipRotator(ctx); WicTransforms.AddCropper(ctx); WicTransforms.AddPixelFormatConverter(ctx); WicTransforms.AddHybridScaler(ctx); WicTransforms.AddScaler(ctx); WicTransforms.AddColorspaceConverter(ctx); MagicTransforms.AddMatte(ctx); MagicTransforms.AddPad(ctx); WicTransforms.AddIndexedColorConverter(ctx); using var enc = new WicImageEncoder(ctx.Settings.SaveFormat, ostm); using var frm = new WicImageEncoderFrame(ctx, enc); frm.WriteSource(ctx); enc.Commit(); return(new ProcessImageResult(ctx.UsedSettings, ctx.Stats)); }
public WicImageEncoderFrame(PipelineContext ctx, WicImageEncoder encoder, PixelArea area = default) { var fmt = ctx.Settings.SaveFormat; var encArea = area.IsEmpty ? ctx.Source.Area : area; var colorMode = ctx.Settings.ColorProfileMode; var bag = default(IPropertyBag2); encoder.WicEncoder.CreateNewFrame(out var frame, ref bag); encoderFrame = ComHandle.Wrap(frame); using (var cbag = ComHandle.Wrap(bag)) { if (fmt == FileFormat.Jpeg) { bag.Write("ImageQuality", ctx.Settings.JpegQuality / 100f); } if (fmt == FileFormat.Jpeg && ctx.Settings.JpegSubsampleMode != ChromaSubsampleMode.Default) { bag.Write("JpegYCrCbSubsampling", (byte)ctx.Settings.JpegSubsampleMode); } if (fmt == FileFormat.Tiff) { bag.Write("TiffCompressionMethod", (byte)WICTiffCompressionOption.WICTiffCompressionNone); } if (fmt == FileFormat.Bmp && ctx.Source.Format.AlphaRepresentation != PixelAlphaRepresentation.None) { bag.Write("EnableV5Header32bppBGRA", true); } frame.Initialize(bag); } frame.SetSize((uint)encArea.Width, (uint)encArea.Height); frame.SetResolution(ctx.Settings.DpiX > 0d ? ctx.Settings.DpiX : ctx.ImageFrame.DpiX, ctx.Settings.DpiY > 0d ? ctx.Settings.DpiY : ctx.ImageFrame.DpiY); bool copySourceMetadata = ctx.ImageFrame is WicImageFrame srcFrame && srcFrame.WicMetadataReader is not null && ctx.Settings.MetadataNames != Enumerable.Empty <string>(); bool writeOrientation = ctx.Settings.OrientationMode == OrientationMode.Preserve && ctx.ImageFrame.ExifOrientation != Orientation.Normal; bool writeColorContext = colorMode == ColorProfileMode.NormalizeAndEmbed || colorMode == ColorProfileMode.Preserve || (colorMode == ColorProfileMode.Normalize && ctx.DestColorProfile != ColorProfile.sRGB && ctx.DestColorProfile != ColorProfile.sGrey); if ((copySourceMetadata || writeOrientation) && frame.TryGetMetadataQueryWriter(out var metawriter)) { using var cmeta = ComHandle.Wrap(metawriter); if (copySourceMetadata) { var wicFrame = (WicImageFrame)ctx.ImageFrame; foreach (string prop in ctx.Settings.MetadataNames) { if (wicFrame.WicMetadataReader !.TryGetMetadataByName(prop, out var pvar) && pvar.Value is not null) { metawriter.TrySetMetadataByName(prop, pvar); } } } if (writeOrientation) { string orientationPath = ctx.Settings.SaveFormat == FileFormat.Jpeg ? Wic.Metadata.OrientationJpeg : Wic.Metadata.OrientationExif; metawriter.TrySetMetadataByName(orientationPath, new PropVariant((ushort)ctx.ImageFrame.ExifOrientation)); } } if (writeColorContext) { Debug.Assert(ctx.WicContext.DestColorContext is not null || ctx.DestColorProfile is not null); var cc = ctx.WicContext.DestColorContext; if (ctx.DestColorProfile == ColorProfile.sRGB) { cc = WicColorProfile.SrgbCompact.Value.WicColorContext; } else if (ctx.DestColorProfile == ColorProfile.sGrey) { cc = WicColorProfile.GreyCompact.Value.WicColorContext; } else if (ctx.DestColorProfile == ColorProfile.AdobeRgb) { cc = WicColorProfile.AdobeRgb.Value.WicColorContext; } else if (ctx.DestColorProfile == ColorProfile.DisplayP3) { cc = WicColorProfile.DisplayP3Compact.Value.WicColorContext; } frame.TrySetColorContexts(cc ?? ctx.WicContext.AddRef(WicColorProfile.CreateContextFromProfile(ctx.DestColorProfile !.ProfileBytes))); } }
public WicImageEncoderFrame(PipelineContext ctx, WicImageEncoder encoder, PixelArea area = default) { var fmt = ctx.Settings.SaveFormat; var encArea = area.IsEmpty ? ctx.Source.Area : area; var colorMode = ctx.Settings.ColorProfileMode; using var frame = default(ComPtr <IWICBitmapFrameEncode>); using (var pbag = default(ComPtr <IPropertyBag2>)) { HRESULT.Check(encoder.WicEncoder->CreateNewFrame(frame.GetAddressOf(), pbag.GetAddressOf())); if (fmt == FileFormat.Jpeg) { pbag.Write("ImageQuality", ctx.Settings.JpegQuality / 100f); } if (fmt == FileFormat.Jpeg && ctx.Settings.JpegSubsampleMode != ChromaSubsampleMode.Default) { pbag.Write("JpegYCrCbSubsampling", (byte)ctx.Settings.JpegSubsampleMode); } if (fmt == FileFormat.Tiff) { pbag.Write("TiffCompressionMethod", (byte)WICTiffCompressionOption.WICTiffCompressionNone); } if (fmt == FileFormat.Bmp && ctx.Source.Format.AlphaRepresentation != PixelAlphaRepresentation.None) { pbag.Write("EnableV5Header32bppBGRA", true); } HRESULT.Check(frame.Get()->Initialize(pbag)); } HRESULT.Check(frame.Get()->SetSize((uint)encArea.Width, (uint)encArea.Height)); HRESULT.Check(frame.Get()->SetResolution(ctx.Settings.DpiX > 0d ? ctx.Settings.DpiX : ctx.ImageFrame.DpiX, ctx.Settings.DpiY > 0d ? ctx.Settings.DpiY : ctx.ImageFrame.DpiY)); bool copySourceMetadata = ctx.ImageFrame is WicImageFrame srcFrame && srcFrame.WicMetadataReader is not null && ctx.Settings.MetadataNames != Enumerable.Empty <string>(); bool writeOrientation = ctx.Settings.OrientationMode == OrientationMode.Preserve && ctx.ImageFrame.ExifOrientation != Orientation.Normal; bool writeColorContext = colorMode == ColorProfileMode.NormalizeAndEmbed || colorMode == ColorProfileMode.Preserve || (colorMode == ColorProfileMode.Normalize && ctx.DestColorProfile != ColorProfile.sRGB && ctx.DestColorProfile != ColorProfile.sGrey); using var metawriter = default(ComPtr <IWICMetadataQueryWriter>); if ((copySourceMetadata || writeOrientation) && SUCCEEDED(frame.Get()->GetMetadataQueryWriter(metawriter.GetAddressOf()))) { if (copySourceMetadata) { var wicFrame = (WicImageFrame)ctx.ImageFrame; foreach (string prop in ctx.Settings.MetadataNames) { var pv = default(PROPVARIANT); if (SUCCEEDED(wicFrame.WicMetadataReader->GetMetadataByName(prop, &pv)) && pv.vt != (ushort)VARENUM.VT_EMPTY) { _ = metawriter.Get()->SetMetadataByName(prop, &pv); } } } if (writeOrientation) { string orientationPath = ctx.Settings.SaveFormat == FileFormat.Jpeg ? Wic.Metadata.OrientationJpeg : Wic.Metadata.OrientationExif; var pv = new PROPVARIANT { vt = (ushort)VARENUM.VT_UI2 }; pv.Anonymous.uiVal = (ushort)ctx.ImageFrame.ExifOrientation; _ = metawriter.Get()->SetMetadataByName(orientationPath, &pv); } } if (writeColorContext) { Debug.Assert(ctx.WicContext.DestColorContext is not null || ctx.DestColorProfile is not null); var cc = ctx.WicContext.DestColorContext; if (ctx.DestColorProfile == ColorProfile.sRGB) { cc = WicColorProfile.SrgbCompact.Value.WicColorContext; } else if (ctx.DestColorProfile == ColorProfile.sGrey) { cc = WicColorProfile.GreyCompact.Value.WicColorContext; } else if (ctx.DestColorProfile == ColorProfile.AdobeRgb) { cc = WicColorProfile.AdobeRgb.Value.WicColorContext; } else if (ctx.DestColorProfile == ColorProfile.DisplayP3) { cc = WicColorProfile.DisplayP3Compact.Value.WicColorContext; } using var ccc = default(ComPtr <IWICColorContext>); if (cc is null) { ccc.Attach(WicColorProfile.CreateContextFromProfile(ctx.DestColorProfile !.ProfileBytes)); cc = ccc; } _ = frame.Get()->SetColorContexts(1, &cc); } WicEncoderFrame = frame.Detach(); }
public WicImageEncoderFrame(PipelineContext ctx, WicImageEncoder encoder, PixelArea area = default) { var fmt = ctx.Settings.SaveFormat; var encArea = area.IsEmpty ? ctx.Source.Area : area; var colorMode = ctx.Settings.ColorProfileMode; using var frame = default(ComPtr <IWICBitmapFrameEncode>); using (var pbag = default(ComPtr <IPropertyBag2>)) { HRESULT.Check(encoder.WicEncoder->CreateNewFrame(frame.GetAddressOf(), pbag.GetAddressOf())); if (fmt == FileFormat.Jpeg) { pbag.Write("ImageQuality", ctx.Settings.JpegQuality / 100f); } if (fmt == FileFormat.Jpeg && ctx.Settings.JpegSubsampleMode != ChromaSubsampleMode.Default) { pbag.Write("JpegYCrCbSubsampling", (byte)ctx.Settings.JpegSubsampleMode); } if (fmt == FileFormat.Tiff) { pbag.Write("TiffCompressionMethod", (byte)WICTiffCompressionOption.WICTiffCompressionNone); } if (fmt == FileFormat.Bmp && ctx.Source.Format.AlphaRepresentation != PixelAlphaRepresentation.None) { pbag.Write("EnableV5Header32bppBGRA", true); } HRESULT.Check(frame.Get()->Initialize(pbag)); } HRESULT.Check(frame.Get()->SetSize((uint)encArea.Width, (uint)encArea.Height)); HRESULT.Check(frame.Get()->SetResolution(ctx.Settings.DpiX > 0d ? ctx.Settings.DpiX : ctx.ImageFrame.DpiX, ctx.Settings.DpiY > 0d ? ctx.Settings.DpiY : ctx.ImageFrame.DpiY)); bool copySourceMetadata = ctx.ImageFrame is WicImageFrame srcFrame && srcFrame.WicMetadataReader is not null && ctx.Settings.MetadataNames != Enumerable.Empty <string>(); bool writeOrientation = ctx.Settings.OrientationMode == OrientationMode.Preserve && ctx.ImageFrame.ExifOrientation != Orientation.Normal; bool writeColorContext = colorMode == ColorProfileMode.NormalizeAndEmbed || colorMode == ColorProfileMode.Preserve || (colorMode == ColorProfileMode.Normalize && ctx.DestColorProfile != ColorProfile.sRGB && ctx.DestColorProfile != ColorProfile.sGrey); using var metawriter = default(ComPtr <IWICMetadataQueryWriter>); if ((copySourceMetadata || writeOrientation) && SUCCEEDED(frame.Get()->GetMetadataQueryWriter(metawriter.GetAddressOf()))) { if (copySourceMetadata) { var wicFrame = (WicImageFrame)ctx.ImageFrame; foreach (string prop in ctx.Settings.MetadataNames) { var pv = default(PROPVARIANT); if (SUCCEEDED(wicFrame.WicMetadataReader->GetMetadataByName(prop, &pv)) && pv.vt != (ushort)VARENUM.VT_EMPTY) { _ = metawriter.Get()->SetMetadataByName(prop, &pv); } } } if (writeOrientation) { string orientationPath = ctx.Settings.SaveFormat == FileFormat.Jpeg ? Wic.Metadata.OrientationJpeg : Wic.Metadata.OrientationExif; var pv = new PROPVARIANT { vt = (ushort)VARENUM.VT_UI2 }; pv.Anonymous.uiVal = (ushort)ctx.ImageFrame.ExifOrientation; _ = metawriter.Get()->SetMetadataByName(orientationPath, &pv); } } if (writeColorContext) { Debug.Assert(ctx.WicContext.DestColorContext is not null || ctx.DestColorProfile is not null); var cc = ctx.WicContext.DestColorContext; if (ctx.DestColorProfile == ColorProfile.sRGB) { cc = WicColorProfile.SrgbCompact.Value.WicColorContext; } else if (ctx.DestColorProfile == ColorProfile.sGrey) { cc = WicColorProfile.GreyCompact.Value.WicColorContext; } else if (ctx.DestColorProfile == ColorProfile.AdobeRgb) { cc = WicColorProfile.AdobeRgb.Value.WicColorContext; } else if (ctx.DestColorProfile == ColorProfile.DisplayP3) { cc = WicColorProfile.DisplayP3Compact.Value.WicColorContext; } // WIC writes gAMA and cHRM tags along with iCCP when SetColorContexts is called on a PNG frame. // Chromium ignores the iCCP tag if the others are present, so we try to write it alone explicitly. if (fmt == FileFormat.Png && ctx.DestColorProfile is not null && metawriter.Get() is not null) { var name = (ReadOnlySpan <byte>) new[] { (byte)'I', (byte)'C', (byte)'C', (byte)'\0' }; fixed(byte *pprofile = ctx.DestColorProfile.ProfileBytes) { var pvn = new PROPVARIANT { vt = (ushort)VARENUM.VT_LPSTR }; pvn.Anonymous.pszVal = (sbyte *)Unsafe.AsPointer(ref MemoryMarshal.GetReference(name)); _ = metawriter.Get()->SetMetadataByName(Wic.Metadata.Png.IccProfileName, &pvn); var pvv = new PROPVARIANT { vt = (ushort)(VARENUM.VT_UI1 | VARENUM.VT_VECTOR) }; pvv.Anonymous.blob.pBlobData = pprofile; pvv.Anonymous.blob.cbSize = (uint)ctx.DestColorProfile.ProfileBytes.Length; _ = metawriter.Get()->SetMetadataByName(Wic.Metadata.Png.IccProfileData, &pvv); } } else { using var ccc = default(ComPtr <IWICColorContext>); if (cc is null) { ccc.Attach(WicColorProfile.CreateContextFromProfile(ctx.DestColorProfile !.ProfileBytes)); cc = ccc; } _ = frame.Get()->SetColorContexts(1, &cc); } }