Ejemplo n.º 1
0
        public static void AddPlanarCache(WicProcessingContext ctx)
        {
            if (!(ctx.Source.WicSource is IWICPlanarBitmapSourceTransform trans))
            {
                throw new NotSupportedException("Transform chain doesn't support planar mode.  Only JPEG Decoder, Rotator, Scaler, and PixelFormatConverter are allowed");
            }

            double rat    = ctx.Settings.HybridScaleRatio.Clamp(1d, 8d);
            uint   width  = (uint)Math.Ceiling(ctx.Source.Width / rat);
            uint   height = (uint)Math.Ceiling(ctx.Source.Height / rat);

            var opt  = ctx.DecoderFrame.ExifOrientation.ToWicTransformOptions();
            var desc = new WICBitmapPlaneDescription[2];

            if (!trans.DoesSupportTransform(ref width, ref height, opt, WICPlanarOptions.WICPlanarOptionsDefault, planarPixelFormats, desc, 2))
            {
                throw new NotSupportedException("Requested planar transform not supported");
            }

            var cacheSource = ctx.AddDispose(new WicPlanarCache(trans, desc[0], desc[1], ctx.Settings.Crop, opt, width, height, rat));

            ctx.PlanarChromaSource = cacheSource.GetPlane(WicPlane.Chroma);
            ctx.PlanarLumaSource   = cacheSource.GetPlane(WicPlane.Luma);
            ctx.Source             = ctx.PlanarChromaSource;
            ctx.Source             = ctx.PlanarLumaSource;
        }
Ejemplo n.º 2
0
        public WicFrameReader(WicDecoder dec, WicProcessingContext ctx)
        {
            Frame   = AddRef(dec.Decoder.GetFrame((uint)ctx.Settings.FrameIndex));
            Source  = Frame;
            Context = ctx;

            if (ctx.ContainerFormat == Consts.GUID_ContainerFormatRaw && ctx.Settings.FrameIndex == 0)
            {
                try { Source = AddRef(dec.Decoder.GetPreview()); } catch { }
            }

            ctx.PixelFormat = Source.GetPixelFormat();
            Source.GetSize(out ctx.Width, out ctx.Height);

            var ptrans = Source as IWICPlanarBitmapSourceTransform;

            if (ptrans != null)
            {
                uint pw = ctx.Width, ph = ctx.Height;
                var  pdesc = new WICBitmapPlaneDescription[2];
                var  pfmts = new Guid[] { Consts.GUID_WICPixelFormat8bppY, Consts.GUID_WICPixelFormat16bppCbCr };
                ctx.SupportsPlanar = ptrans.DoesSupportTransform(ref pw, ref ph, WICBitmapTransformOptions.WICBitmapTransformRotate0, WICPlanarOptions.WICPlanarOptionsPreserveSubsampling, pfmts, pdesc, 2);
                ctx.IsSubsampled   = pdesc[0].Width != pdesc[1].Width || pdesc[0].Height != pdesc[1].Height;
            }
        }
Ejemplo n.º 3
0
        public WicPlanarCacheSource(IWICPlanarBitmapSourceTransform source, WICBitmapPlaneDescription descY, WICBitmapPlaneDescription descC, WICRect crop, WICBitmapTransformOptions transformOptions, uint width, uint height, double ratio)
        {
            // TODO fractional ratio support?
            subsampleRatioX = Math.Ceiling((double)descY.Width / descC.Width);
            subsampleRatioY = Math.Ceiling((double)descY.Height / descC.Height);

            var scrop = new WICRect();

            scrop.X      = (int)Math.Floor(crop.X / ratio);
            scrop.Y      = (int)Math.Floor(crop.Y / ratio);
            scrop.Width  = Math.Min((int)Math.Ceiling(crop.Width / ratio), (int)descY.Width);
            scrop.Height = Math.Min((int)Math.Ceiling(crop.Height / ratio), (int)descY.Height);

            if (subsampleRatioX > 1d)
            {
                descC.Width = Math.Min((uint)Math.Ceiling(scrop.Width / subsampleRatioX), descC.Width);
                descY.Width = (uint)Math.Min(descC.Width * subsampleRatioX, scrop.Width);

                if (scrop.X % subsampleRatioX > 0)
                {
                    scrop.X = (int)(scrop.X / subsampleRatioX) * (int)subsampleRatioX;
                }
            }
            else
            {
                descC.Width = descY.Width = (uint)scrop.Width;
            }

            if (subsampleRatioY > 1d)
            {
                descC.Height = Math.Min((uint)Math.Ceiling(scrop.Height / subsampleRatioY), descC.Height);
                descY.Height = (uint)Math.Min(descC.Height * subsampleRatioY, scrop.Height);

                if (scrop.Y % subsampleRatioY > 0)
                {
                    scrop.Y = (int)(scrop.Y / subsampleRatioY) * (int)subsampleRatioY;
                }
            }
            else
            {
                descC.Height = descY.Height = (uint)scrop.Height;
            }

            sourceTransform        = source;
            sourceTransformOptions = transformOptions;
            planeDescriptionY      = descY;
            planeDescriptionC      = descC;
            scaledCrop             = scrop;
            scaledWidth            = width;
            scaledHeight           = height;

            strideY     = (uint)scrop.Width + 3u & ~3u;
            buffHeightY = 16u;

            strideC     = (uint)(Math.Ceiling(scrop.Width / subsampleRatioX)) * 2u + 3u & ~3u;
            buffHeightC = (uint)(buffHeightY / subsampleRatioY);

            sourceY = new WicPlanarSource(this, WicPlane.Luma, descY);
            sourceC = new WicPlanarSource(this, WicPlane.Chroma, descC);
        }
Ejemplo n.º 4
0
        public PlanarPixelSource(WicPlanarCache cache, WicPlane plane, WICBitmapPlaneDescription planeDesc)
        {
            Width  = planeDesc.Width;
            Height = planeDesc.Height;
            Format = PixelFormat.Cache[planeDesc.Format];

            cacheSource = cache;
            cachePlane  = plane;
        }
Ejemplo n.º 5
0
        public WicPlanarSource(WicPlanarCacheSource cache, WicPlane plane, WICBitmapPlaneDescription planeDesc)
        {
            Width  = planeDesc.Width;
            Height = planeDesc.Height;
            Format = planeDesc.Format;

            cacheSource = cache;
            cachePlane  = plane;
        }
Ejemplo n.º 6
0
        public WicFrameReader(WicDecoder dec, WicProcessingContext ctx) : base(ctx)
        {
            Frame  = AddRef(dec.Decoder.GetFrame((uint)ctx.Settings.FrameIndex));
            Source = Frame;

            if (ctx.ContainerFormat == Consts.GUID_ContainerFormatRaw && ctx.Settings.FrameIndex == 0 && dec.Decoder.TryGetPreview(out var preview))
            {
                Source = AddRef(preview);
            }

            ctx.PixelFormat = PixelFormat.Cache[Source.GetPixelFormat()];
            Source.GetSize(out ctx.Width, out ctx.Height);
            Source.GetResolution(out ctx.DpiX, out ctx.DpiY);

            if (Source is IWICPlanarBitmapSourceTransform ptrans)
            {
                uint pw = ctx.Width, ph = ctx.Height;
                var  pdesc = new WICBitmapPlaneDescription[2];
                var  pfmts = new Guid[] { Consts.GUID_WICPixelFormat8bppY, Consts.GUID_WICPixelFormat16bppCbCr };
                ctx.SupportsPlanar = ptrans.DoesSupportTransform(ref pw, ref ph, WICBitmapTransformOptions.WICBitmapTransformRotate0, WICPlanarOptions.WICPlanarOptionsDefault, pfmts, pdesc, 2);
            }
        }
        public WicPlanarCache(WicTransform prev) : base(prev)
        {
            if (!(prev.Source is IWICPlanarBitmapSourceTransform))
            {
                throw new NotSupportedException("Transform chain doesn't support planar mode.  Only JPEG Decoder, Rotator, Scaler, and ColorSpaceConverter are allowed");
            }
            var trans = (IWICPlanarBitmapSourceTransform)prev.Source;

            double rat = Context.Settings.HybridScaleRatio.Clamp(1d, 8d);

            Context.Width  = (uint)Math.Ceiling(Context.Width / rat);
            Context.Height = (uint)Math.Ceiling(Context.Height / rat);

            // Although generally the last scan has the least significant bit(s) of the luma plane and skipping it could be very beneficial performance-wise, there is no guarantee of scan order.  Might be able to do something with more decoder support.
            //var prog = Frame as IWICProgressiveLevelControl;
            //if (prog != null)
            //{
            //	uint levels = prog.GetLevelCount();
            //	uint level = (uint)Math.Ceiling(levels / rat) + (Context.Settings.HybridMode == HybridScaleMode.FavorQuality || Context.Settings.HybridMode == HybridScaleMode.Off ? (uint)Math.Ceiling(levels / 8d) : 0u);
            //	prog.SetCurrentLevel(Math.Min(level, levels - (Context.Settings.ScaleRatio >= 2d && levels > 7u ? 2u : 1u)));
            //}

            var fmts = new Guid[] { Consts.GUID_WICPixelFormat8bppY, Consts.GUID_WICPixelFormat16bppCbCr };
            var desc = new WICBitmapPlaneDescription[2];

            if (!trans.DoesSupportTransform(ref Context.Width, ref Context.Height, Context.TransformOptions, WICPlanarOptions.WICPlanarOptionsDefault, fmts, desc, 2))
            {
                throw new NotSupportedException("Requested planar transform not supported");
            }

            var crop = new WICRect {
                X = Context.Settings.Crop.X, Y = Context.Settings.Crop.Y, Width = Context.Settings.Crop.Width, Height = Context.Settings.Crop.Height
            };

            cacheSource = new WicPlanarCacheSource(trans, desc[0], desc[1], crop, Context.TransformOptions, Context.Width, Context.Height, rat, Context.NeedsCache);

            SourceY    = cacheSource.GetPlane(WicPlane.Luma);
            SourceCbCr = cacheSource.GetPlane(WicPlane.Chroma);
        }
Ejemplo n.º 8
0
        public WicPlanarCache(WicTransform prev) : base(prev)
        {
            Contract.Requires <NotSupportedException>(prev.Source is IWICPlanarBitmapSourceTransform, "Transform chain doesn't support planar mode.  Only JPEG Decoder, Rotator, Scaler, and ColorSpaceConverter are allowed");
            var trans = (IWICPlanarBitmapSourceTransform)prev.Source;

            double rat = Context.Settings.HybridScaleRatio.Clamp(1d, 8d);

            Context.Width  = (uint)Math.Ceiling(Context.Width / rat);
            Context.Height = (uint)Math.Ceiling(Context.Height / rat);

            var prog = Frame as IWICProgressiveLevelControl;

            if (prog != null)             // TODO needs work
            {
                uint levels = prog.GetLevelCount();
                uint level  = (uint)Math.Ceiling(levels / rat) + (Context.Settings.HybridMode == HybridScaleMode.FavorQuality || Context.Settings.HybridMode == HybridScaleMode.Off ? (uint)Math.Ceiling(levels / 8d) : 0u);
                prog.SetCurrentLevel(Math.Min(level, levels - (Context.Settings.ScaleRatio >= 2d && levels > 7u ? 2u : 1u)));
            }

            var fmts = new Guid[] { Consts.GUID_WICPixelFormat8bppY, Consts.GUID_WICPixelFormat16bppCbCr };
            var desc = new WICBitmapPlaneDescription[2];

            if (!trans.DoesSupportTransform(ref Context.Width, ref Context.Height, Context.TransformOptions, WICPlanarOptions.WICPlanarOptionsPreserveSubsampling, fmts, desc, 2))
            {
                throw new NotSupportedException("Planar Transform not supported");
            }

            var crop = new WICRect()
            {
                X = Context.Settings.Crop.X, Y = Context.Settings.Crop.Y, Width = Context.Settings.Crop.Width, Height = Context.Settings.Crop.Height
            };
            var source = new WicPlanarCacheSource(trans, desc[0], desc[1], crop, Context.TransformOptions, Context.Width, Context.Height, rat);

            SourceY    = source.GetPlane(WicPlane.Luma);
            SourceCbCr = source.GetPlane(WicPlane.Chroma);
        }
Ejemplo n.º 9
0
        public WicFrameReader(WicProcessingContext ctx, bool planar = false)
        {
            ctx.DecoderFrame = this;

            if (ctx.Decoder.Decoder is null)
            {
                DpiX = DpiY = 96d;
                return;
            }

            var source = default(IWICBitmapSource);

            source = Frame = ctx.AddRef(ctx.Decoder.Decoder.GetFrame((uint)ctx.Settings.FrameIndex));

            if (ctx.Decoder.WicContainerFormat == Consts.GUID_ContainerFormatRaw && ctx.Settings.FrameIndex == 0 && ctx.Decoder.Decoder.TryGetPreview(out var preview))
            {
                source = ctx.AddRef(preview);
            }

            source.GetResolution(out double dpix, out double dpiy);
            DpiX = dpix;
            DpiY = dpiy;

            if (PixelFormat.Cache[source.GetPixelFormat()].NumericRepresentation == PixelNumericRepresentation.Indexed)
            {
                var pal = ctx.AddRef(Wic.Factory.CreatePalette());
                source.CopyPalette(pal);

                var newFormat = Consts.GUID_WICPixelFormat24bppBGR;
                if (pal.HasAlpha())
                {
                    newFormat = Consts.GUID_WICPixelFormat32bppBGRA;
                }
                else if (pal.IsGrayscale() || pal.IsBlackWhite())
                {
                    newFormat = Consts.GUID_WICPixelFormat8bppGray;
                }

                var conv = ctx.AddRef(Wic.Factory.CreateFormatConverter());
                conv.Initialize(source, newFormat, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.0, WICBitmapPaletteType.WICBitmapPaletteTypeCustom);
                source = conv;
            }

            if (source is IWICBitmapSourceTransform trans)
            {
                uint pw = 1, ph = 1;
                source.GetSize(out uint ow, out uint oh);
                trans.GetClosestSize(ref pw, ref ph);
                SupportsNativeScale     = pw < ow || ph < oh;
                SupportsNativeTransform = trans.DoesSupportTransform(WICBitmapTransformOptions.WICBitmapTransformRotate270);
            }

            if (planar && source is IWICPlanarBitmapSourceTransform ptrans)
            {
                uint pw = 1, ph = 1;
                var  pdesc = new WICBitmapPlaneDescription[2];
                var  pfmts = new[] { Consts.GUID_WICPixelFormat8bppY, Consts.GUID_WICPixelFormat16bppCbCr };
                SupportsPlanarPipeline = ptrans.DoesSupportTransform(ref pw, ref ph, WICBitmapTransformOptions.WICBitmapTransformRotate0, WICPlanarOptions.WICPlanarOptionsDefault, pfmts, pdesc, 2);
            }

            bool preserveNative = SupportsPlanarPipeline || SupportsNativeTransform || (SupportsNativeScale && ctx.Settings.HybridScaleRatio > 1d);

            ctx.Source = source.AsPixelSource(nameof(IWICBitmapFrameDecode), !preserveNative);
        }
Ejemplo n.º 10
0
        public static void AddMetadataReader(WicProcessingContext ctx, bool basicOnly = false)
        {
            if (ctx.DecoderFrame.Frame is null)
            {
                return;
            }

            if (ctx.DecoderFrame.Frame.TryGetMetadataQueryReader(out var metareader))
            {
                ctx.AddRef(metareader);

                // Exif orientation
                var pvorient = default(PropVariant);
                if (ctx.Settings.OrientationMode != OrientationMode.Ignore && metareader.TryGetMetadataByName("System.Photo.Orientation", out pvorient))
                {
#pragma warning disable 0618 // VarEnum is obsolete
                    if (ctx.Settings.OrientationMode == OrientationMode.Normalize && pvorient.UnmanagedType == VarEnum.VT_UI2)
                    {
                        ctx.DecoderFrame.ExifOrientation = (Orientation)Math.Min(Math.Max((ushort)Orientation.Normal, (ushort)pvorient.Value), (ushort)Orientation.Rotate270);
                    }
#pragma warning restore 0618

                    var opt = ctx.DecoderFrame.ExifOrientation.ToWicTransformOptions();
                    if (ctx.DecoderFrame.SupportsPlanarPipeline && opt != WICBitmapTransformOptions.WICBitmapTransformRotate0 && ctx.DecoderFrame.Frame is IWICPlanarBitmapSourceTransform ptrans)
                    {
                        uint pw = 1, ph = 1;
                        var  desc = new WICBitmapPlaneDescription[2];
                        ctx.DecoderFrame.SupportsPlanarPipeline = ptrans.DoesSupportTransform(ref pw, ref ph, opt, WICPlanarOptions.WICPlanarOptionsDefault, planarPixelFormats, desc, 2);
                    }
                }

                if (basicOnly)
                {
                    return;
                }

                // other requested properties
                var propdic = new Dictionary <string, PropVariant>();
                foreach (string prop in ctx.Settings.MetadataNames ?? Enumerable.Empty <string>())
                {
                    if (metareader.TryGetMetadataByName(prop, out var pvar) && pvar.Value != null)
                    {
                        propdic[prop] = pvar;
                    }
                }

                if (ctx.Settings.OrientationMode == OrientationMode.Preserve && pvorient != null)
                {
                    propdic["System.Photo.Orientation"] = pvorient;
                }

                ctx.DecoderFrame.Metadata = propdic;
            }

            if (basicOnly)
            {
                return;
            }

            // ICC profiles
            //http://ninedegreesbelow.com/photography/embedded-color-space-information.html
            uint ccc      = ctx.DecoderFrame.Frame.GetColorContextCount();
            var  fmt      = ctx.Source.Format;
            var  profiles = new IWICColorContext[ccc];
            var  profile  = default(IWICColorContext);

            if (ccc > 0)
            {
                for (int i = 0; i < ccc; i++)
                {
                    profiles[i] = ctx.AddRef(Wic.Factory.CreateColorContext());
                }

                ctx.DecoderFrame.Frame.GetColorContexts(ccc, profiles);
            }

            foreach (var cc in profiles)
            {
                var cct = cc.GetType();
                if (cct == WICColorContextType.WICColorContextProfile)
                {
                    int ccs = (int)cc.GetProfileBytes(0, null);

                    // don't try to read giant profiles. 4MiB is more than enough
                    if ((uint)ccs > (1024 * 1024 * 4))
                    {
                        continue;
                    }

                    using (var ccb = MemoryPool <byte> .Shared.Rent(ccs))
                    {
                        MemoryMarshal.TryGetArray(ccb.Memory.Slice(0, ccs), out ArraySegment <byte> cca);
                        cc.GetProfileBytes((uint)cca.Count, cca.Array);
                        var cpi = ColorProfile.Cache.GetOrAdd(cca);

                        // match only color profiles that match our intended use. if we have a standard sRGB profile, don't save it; we don't need to convert
                        if (cpi.IsValid && (
                                (cpi.DataColorSpace == ColorProfile.ProfileColorSpace.Rgb && (fmt.ColorRepresentation == PixelColorRepresentation.Bgr || fmt.ColorRepresentation == PixelColorRepresentation.Rgb) && !cpi.IsSrgb) ||
                                (cpi.DataColorSpace == ColorProfile.ProfileColorSpace.Grey && fmt.ColorRepresentation == PixelColorRepresentation.Grey && !cpi.IsSrgbCurve) ||
                                (cpi.DataColorSpace == ColorProfile.ProfileColorSpace.Cmyk && fmt.ColorRepresentation == PixelColorRepresentation.Cmyk)
                                ))
                        {
                            profile = cc;
                            if (cpi.IsRgbMatrix || cpi.IsGreyTrc)
                            {
                                ctx.SourceColorProfile = cpi;
                            }
                            break;
                        }
                    }
                }
                else if (cct == WICColorContextType.WICColorContextExifColorSpace && cc.GetExifColorSpace() == ExifColorSpace.AdobeRGB)
                {
                    profile = cc;
                    break;
                }
            }

            var defaultColorContext = fmt.ColorRepresentation == PixelColorRepresentation.Grey ? Wic.GreyContext.Value : Wic.SrgbContext.Value;
            ctx.SourceColorContext = profile ?? (fmt.ColorRepresentation == PixelColorRepresentation.Cmyk ? Wic.CmykContext.Value : null);
            ctx.DestColorContext   = ctx.Settings.ColorProfileMode <= ColorProfileMode.NormalizeAndEmbed || ctx.SourceColorContext is null ? defaultColorContext : ctx.SourceColorContext;

            var defaultColorProfile = fmt.ColorRepresentation == PixelColorRepresentation.Grey ? ColorProfile.sGrey : ColorProfile.sRGB;
            ctx.SourceColorProfile = ctx.SourceColorProfile ?? defaultColorProfile;
            ctx.DestColorProfile   = ctx.Settings.ColorProfileMode <= ColorProfileMode.NormalizeAndEmbed ? defaultColorProfile : ctx.SourceColorProfile;
        }
Ejemplo n.º 11
0
        public WicPlanarCache(IWICPlanarBitmapSourceTransform source, WICBitmapPlaneDescription descY, WICBitmapPlaneDescription descC, WICRect crop, WICBitmapTransformOptions transformOptions, uint width, uint height, double ratio)
        {
            subsampleRatioX = Math.Ceiling((double)descY.Width / descC.Width);
            subsampleRatioY = Math.Ceiling((double)descY.Height / descC.Height);

            var scrop = new WICRect {
                X      = (int)Math.Floor(crop.X / ratio),
                Y      = (int)Math.Floor(crop.Y / ratio),
                Width  = Math.Min((int)Math.Ceiling(crop.Width / ratio), (int)descY.Width),
                Height = Math.Min((int)Math.Ceiling(crop.Height / ratio), (int)descY.Height)
            };

            if (subsampleRatioX > 1d)
            {
                if (scrop.X % subsampleRatioX > double.Epsilon)
                {
                    scrop.X = (int)(scrop.X / subsampleRatioX) * (int)subsampleRatioX;
                }
                if (scrop.Width % subsampleRatioX > double.Epsilon)
                {
                    scrop.Width = (int)Math.Min(Math.Ceiling(scrop.Width / subsampleRatioX) * (int)subsampleRatioX, descY.Width - scrop.X);
                }

                descC.Width = Math.Min((uint)Math.Ceiling(scrop.Width / subsampleRatioX), descC.Width);
                descY.Width = (uint)Math.Min(descC.Width * subsampleRatioX, scrop.Width);
            }
            else
            {
                descC.Width = descY.Width = (uint)scrop.Width;
            }

            if (subsampleRatioY > 1d)
            {
                if (scrop.Y % subsampleRatioY > double.Epsilon)
                {
                    scrop.Y = (int)(scrop.Y / subsampleRatioY) * (int)subsampleRatioY;
                }
                if (scrop.Height % subsampleRatioY > double.Epsilon)
                {
                    scrop.Height = (int)Math.Min(Math.Ceiling(scrop.Height / subsampleRatioY) * (int)subsampleRatioY, descY.Height - scrop.Y);
                }

                descC.Height = Math.Min((uint)Math.Ceiling(scrop.Height / subsampleRatioY), descC.Height);
                descY.Height = (uint)Math.Min(descC.Height * subsampleRatioY, scrop.Height);
            }
            else
            {
                descC.Height = descY.Height = (uint)scrop.Height;
            }

            sourceTransform        = source;
            sourceTransformOptions = transformOptions;
            scaledCrop             = scrop;
            scaledWidth            = width;
            scaledHeight           = height;

            strideY     = scrop.Width + 3 & ~3;
            strideC     = (int)Math.Ceiling(scrop.Width / subsampleRatioX) * 2 + 3 & ~3;
            buffHeightY = Math.Min(scrop.Height, transformOptions.RequiresCache() ? scrop.Height : 16);
            buffHeightC = (int)Math.Ceiling(buffHeightY / subsampleRatioY);

            sourceY = new PlanarPixelSource(this, WicPlane.Luma, descY);
            sourceC = new PlanarPixelSource(this, WicPlane.Chroma, descC);
        }
Ejemplo n.º 12
0
        public static void AddMetadataReader(WicProcessingContext ctx, bool basicOnly = false)
        {
            if (ctx.DecoderFrame.Frame == null)
            {
                return;
            }

            if (ctx.DecoderFrame.Frame.TryGetMetadataQueryReader(out var metareader))
            {
                ctx.AddRef(metareader);

                // Exif orientation
                if (metareader.TryGetMetadataByName("System.Photo.Orientation", out var pv))
                {
#pragma warning disable 0618 // VarEnum is obsolete
                    if (pv.UnmanagedType == VarEnum.VT_UI2)
                    {
                        ctx.DecoderFrame.ExifOrientation = (Orientation)Math.Min(Math.Max((ushort)Orientation.Normal, (ushort)pv.Value), (ushort)Orientation.Rotate270);
                    }
#pragma warning restore 0618

                    var opt = ctx.DecoderFrame.ExifOrientation.ToWicTransformOptions();
                    if (ctx.DecoderFrame.SupportsPlanarPipeline && opt != WICBitmapTransformOptions.WICBitmapTransformRotate0 && ctx.DecoderFrame.Frame is IWICPlanarBitmapSourceTransform ptrans)
                    {
                        uint pw = 1, ph = 1;
                        var  pdesc = new WICBitmapPlaneDescription[2];
                        var  pfmts = new[] { Consts.GUID_WICPixelFormat8bppY, Consts.GUID_WICPixelFormat16bppCbCr };
                        ctx.DecoderFrame.SupportsPlanarPipeline = ptrans.DoesSupportTransform(ref pw, ref ph, opt, WICPlanarOptions.WICPlanarOptionsDefault, pfmts, pdesc, 2);
                    }
                }

                if (basicOnly)
                {
                    return;
                }

                // other requested properties
                var propdic = new Dictionary <string, PropVariant>();
                foreach (string prop in ctx.Settings.MetadataNames ?? Enumerable.Empty <string>())
                {
                    if (metareader.TryGetMetadataByName(prop, out var pvar) && pvar.Value != null)
                    {
                        propdic[prop] = pvar;
                    }
                }

                ctx.DecoderFrame.Metadata = propdic;
            }

            if (basicOnly)
            {
                return;
            }

            // ICC profiles
            //http://ninedegreesbelow.com/photography/embedded-color-space-information.html
            uint ccc      = ctx.DecoderFrame.Frame.GetColorContextCount();
            var  profiles = new IWICColorContext[ccc];
            var  profile  = default(IWICColorContext);

            if (ccc > 0)
            {
                for (int i = 0; i < ccc; i++)
                {
                    profiles[i] = ctx.AddRef(Wic.Factory.CreateColorContext());
                }

                ctx.DecoderFrame.Frame.GetColorContexts(ccc, profiles);
            }

            foreach (var cc in profiles)
            {
                var cct = cc.GetType();
                if (cct == WICColorContextType.WICColorContextProfile)
                {
                    uint ccs = cc.GetProfileBytes(0, null);
                    var  ccb = ArrayPool <byte> .Shared.Rent((int)ccs);

                    cc.GetProfileBytes(ccs, ccb);

                    var cp = new ColorProfileInfo(new ArraySegment <byte>(ccb, 0, (int)ccs));
                    ArrayPool <byte> .Shared.Return(ccb);

                    // match only color profiles that match our intended use. if we have a standard sRGB profile, don't save it; we don't need to convert
                    if (cp.IsValid && ((cp.IsDisplayRgb && !cp.IsStandardSrgb) || (cp.IsCmyk && ctx.Source.Format.ColorRepresentation == PixelColorRepresentation.Cmyk) /* || (Context.IsGreyscale && cp.DataColorSpace == "GRAY") */))
                    {
                        profile = cc;
                        break;
                    }
                }
                else if (cct == WICColorContextType.WICColorContextExifColorSpace && cc.GetExifColorSpace() == ExifColorSpace.AdobeRGB)
                {
                    profile = cc;
                    break;
                }
            }

            ctx.SourceColorContext = profile ?? (ctx.Source.Format.ColorRepresentation == PixelColorRepresentation.Cmyk ? cmykProfile.Value : null);
            ctx.DestColorContext   = srgbProfile.Value;
        }
Ejemplo n.º 13
0
 public WicPlanarCache(IWICPlanarBitmapSourceTransform source, WICBitmapPlaneDescription descY, WICBitmapPlaneDescription descC, in Rectangle crop, WICBitmapTransformOptions transformOptions, uint width, uint height, double ratio)
Ejemplo n.º 14
0
        public WicPlanarCacheSource(IWICPlanarBitmapSourceTransform source, WICBitmapPlaneDescription descY, WICBitmapPlaneDescription descC, WICRect crop, WICBitmapTransformOptions transformOptions, uint width, uint height, double ratio, bool cacheFull)
        {
            this.cacheFull = cacheFull;

            // TODO fractional ratio support?
            subsampleRatioX = Math.Ceiling((double)descY.Width / descC.Width);
            subsampleRatioY = Math.Ceiling((double)descY.Height / descC.Height);

            var scrop = new WICRect {
                X      = (int)Math.Floor(crop.X / ratio),
                Y      = (int)Math.Floor(crop.Y / ratio),
                Width  = Math.Min((int)Math.Ceiling(crop.Width / ratio), (int)descY.Width),
                Height = Math.Min((int)Math.Ceiling(crop.Height / ratio), (int)descY.Height)
            };

            if (subsampleRatioX > 1d)
            {
                if (scrop.X % subsampleRatioX > 0d)
                {
                    scrop.X = (int)(scrop.X / subsampleRatioX) * (int)subsampleRatioX;
                }
                if (scrop.Width % subsampleRatioX > 0d)
                {
                    scrop.Width = (int)Math.Min(Math.Ceiling(scrop.Width / subsampleRatioX) * (int)subsampleRatioX, descY.Width);
                }

                descC.Width = Math.Min((uint)Math.Ceiling(scrop.Width / subsampleRatioX), descC.Width);
                descY.Width = (uint)Math.Min(descC.Width * subsampleRatioX, scrop.Width);
            }
            else
            {
                descC.Width = descY.Width = (uint)scrop.Width;
            }

            if (subsampleRatioY > 1d)
            {
                if (scrop.Y % subsampleRatioY > 0d)
                {
                    scrop.Y = (int)(scrop.Y / subsampleRatioY) * (int)subsampleRatioY;
                }
                if (scrop.Height % subsampleRatioY > 0d)
                {
                    scrop.Height = (int)Math.Min(Math.Ceiling(scrop.Height / subsampleRatioY) * (int)subsampleRatioY, descY.Height);
                }

                descC.Height = Math.Min((uint)Math.Ceiling(scrop.Height / subsampleRatioY), descC.Height);
                descY.Height = (uint)Math.Min(descC.Height * subsampleRatioY, scrop.Height);
            }
            else
            {
                descC.Height = descY.Height = (uint)scrop.Height;
            }

            sourceTransform        = source;
            sourceTransformOptions = transformOptions;
            scaledCrop             = scrop;
            scaledWidth            = width;
            scaledHeight           = height;

            strideY     = scrop.Width + 3 & ~3;
            buffHeightY = Math.Min(scrop.Height, cacheFull ? scrop.Height : 16);

            strideC     = (int)Math.Ceiling(scrop.Width / subsampleRatioX) * 2 + 3 & ~3;
            buffHeightC = (int)Math.Ceiling(buffHeightY / subsampleRatioY);

            sourceY = new WicPlanarSource(this, WicPlane.Luma, descY);
            sourceC = new WicPlanarSource(this, WicPlane.Chroma, descC);
        }