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));
        }
Esempio n. 2
0
        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)));
            }
        }
Esempio n. 3
0
        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();
        }
Esempio n. 4
0
        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);
                }
            }