예제 #1
0
        public void CopyPixels(WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer)
        {
            int cbLine = (prc.Width * Format.BitsPerPixel + 7) / 8;

            if (prc.X < 0 || prc.Y < 0 || prc.Width < 0 || prc.Height < 0 || prc.X + prc.Width > (int)Width || prc.Y + prc.Height > (int)Height)
            {
                throw new ArgumentOutOfRangeException(nameof(prc), "Requested area does not fall within the image bounds");
            }

            if (cbLine > (int)cbStride)
            {
                throw new ArgumentOutOfRangeException(nameof(cbStride), "Stride is too small for the requested area");
            }

            if ((prc.Height - 1) * (int)cbStride + cbLine > (int)cbBufferSize)
            {
                throw new ArgumentOutOfRangeException(nameof(cbBufferSize), "Buffer is to small for the requested area");
            }

            if (pbBuffer == IntPtr.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(pbBuffer), "Buffer pointer is invalid");
            }

            Timer.Restart();
            CopyPixelsInternal(prc, cbStride, cbBufferSize, pbBuffer);
            Timer.Stop();

            var stats = Stats;

            stats.CallCount++;
            stats.PixelCount     += prc.Width * prc.Height;
            stats.ProcessingTime += (double)Timer.ElapsedTicks / Stopwatch.Frequency * 1000;
        }
예제 #2
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);
        }
예제 #3
0
        public unsafe void CopyPixels <T>(WICRect rectangle, int stride, T[] data) where T : struct
        {
            Guard.MustBeGreaterThan(stride, 0, "Stride must be greather than 0");
            Guard.NotNullOrEmpty(data, nameof(data));

            CopyPixels(new IntPtr(&rectangle), stride, data.Length, (IntPtr)Unsafe.AsPointer(ref data[0]));
        }
예제 #4
0
        public unsafe void CopyPixels(WICRect rectangle, int stride, int size, IntPtr data)
        {
            Guard.MustBeGreaterThan(size, 0, "Size must be greather than 0");
            Guard.MustBeGreaterThan(stride, 0, "Stride must be greather than 0");

            CopyPixels(new IntPtr(&rectangle), stride, size, data);
        }
예제 #5
0
        unsafe public override void CopyPixels(WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer)
        {
            fixed(byte *bstart = LineBuff)
            fixed(ushort *igtstart = LookupTables.InverseGamma, atstart = LookupTables.Alpha)
            {
                int oh = prc.Height, oy = prc.Y;

                prc.Height = 1;
                for (int y = 0; y < oh; y++)
                {
                    prc.Y = oy + y;
                    Source.CopyPixels(prc, Stride, Stride, (IntPtr)bstart);

                    ushort *op = (ushort *)pbBuffer + y * cbStride;
                    if (HasAlpha)
                    {
                        mapValuesWithAlpha(bstart, op, igtstart, atstart, (uint)prc.Width * Bpp);
                    }
                    else
                    {
                        mapValues(bstart, op, igtstart, (uint)prc.Width * Bpp);
                    }
                }
            }
        }
예제 #6
0
        unsafe public void CopyPixels(WicPlane plane, WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer)
        {
            if (lineBuffY.Array == null || (plane == WicPlane.Luma && prc.Y + prc.Height > loadedY) || (plane == WicPlane.Chroma && prc.Y + prc.Height > loadedC))
            {
                loadBuffer(plane, prc);
            }

            switch (plane)
            {
            case WicPlane.Luma:
                fixed(byte *pBuffY = lineBuffY.Array)
                for (int y = 0; y < prc.Height; y++)
                {
                    Buffer.MemoryCopy(pBuffY + (prc.Y - startY) * strideY + y * strideY + prc.X, (byte *)pbBuffer + y * cbStride, cbStride, prc.Width);
                }
                nextY = prc.Y + prc.Height - startY;

                break;

            case WicPlane.Chroma:
                fixed(byte *pBuffC = lineBuffC.Array)
                for (int y = 0; y < prc.Height; y++)
                {
                    Buffer.MemoryCopy(pBuffC + (prc.Y - startC) * strideC + y * strideC + prc.X * 2, (byte *)pbBuffer + y * cbStride, cbStride, prc.Width * 2);
                }
                nextC = prc.Y + prc.Height - startC;

                break;
            }
        }
예제 #7
0
        public ConvolutionTransform(PixelSource source, KernelMap <TWeight> mapx, KernelMap <TWeight> mapy, bool lumaMode = false) : base(source)
        {
            var fmt = Format;

            if (lumaMode)
            {
                if (fmt.ColorRepresentation == PixelColorRepresentation.Bgr || fmt.ColorRepresentation == PixelColorRepresentation.Grey)
                {
                    fmt = fmt.NumericRepresentation == PixelNumericRepresentation.Float ? PixelFormat.Grey32BppFloat :
                          fmt.NumericRepresentation == PixelNumericRepresentation.Fixed ? PixelFormat.Grey16BppUQ15 :
                          fmt.NumericRepresentation == PixelNumericRepresentation.UnsignedInteger ? PixelFormat.Cache[Consts.GUID_WICPixelFormat8bppGray] :
                          throw new NotSupportedException("Unsupported pixel format");
                }
                else
                {
                    throw new NotSupportedException("Unsupported pixel format");
                }
            }

            if (!ProcessorMap.TryGetValue(fmt.FormatGuid, out XProcessor))
            {
                throw new NotSupportedException("Unsupported pixel format");
            }

            if (fmt == PixelFormat.Bgr96BppLinearFloat)
            {
                Format = fmt = PixelFormat.Bgrx128BppLinearFloat;
            }
            else if (fmt == PixelFormat.Bgr96BppFloat)
            {
                Format = fmt = PixelFormat.Bgrx128BppFloat;
            }

            YProcessor = ProcessorMap[fmt.FormatGuid];
            XMap       = mapx;
            YMap       = mapy;

            BufferSource = lumaMode;
            SourceRect   = new WICRect {
                Width = (int)Width, Height = 1
            };
            IntStartLine = -mapy.Samples;

            IntBpp     = fmt.BitsPerPixel / 8 / Unsafe.SizeOf <TPixel>() * Unsafe.SizeOf <TWeight>();
            IntStride  = mapy.Samples * IntBpp;
            WorkStride = fmt.BitsPerPixel / 8 * (int)Width + (IntPtr.Size - 1) & ~(IntPtr.Size - 1);

            int lineBuffLen = (BufferSource ? mapy.Samples : 1) * (int)BufferStride;
            int intBuffLen  = mapx.OutPixels * IntStride;
            int workBuffLen = mapy.Samples * WorkStride;

            LineBuff = new ArraySegment <byte>(ArrayPool <byte> .Shared.Rent(lineBuffLen), 0, lineBuffLen).Zero();
            IntBuff  = new ArraySegment <byte>(ArrayPool <byte> .Shared.Rent(intBuffLen), 0, intBuffLen).Zero();
            WorkBuff = lumaMode && !Format.IsBinaryCompatibleWith(fmt) ? new ArraySegment <byte>(ArrayPool <byte> .Shared.Rent(workBuffLen), 0, workBuffLen).Zero() : LineBuff;

            Width  = (uint)mapx.OutPixels;
            Height = (uint)mapy.OutPixels;
        }
예제 #8
0
        unsafe private void applyMatteLinearFloat(WICRect prc, float *pixels, int stride)
        {
            var   igt = LookupTables.InverseGammaFloat;
            float mrl = igt[maskRed], mgl = igt[maskGreen], mbl = igt[maskBlue];

            var v1   = new Vector <float>(1f);
            var vmat = new Vector <float>(new[] { mbl, mgl, mrl, 1f, mbl, mgl, mrl, 1f });
            var vm0  = new Vector <int>(new[] { -1, -1, -1, -1, 0, 0, 0, 0 });
            var vm1  = new Vector <int>(new[] { -1, -1, -1, 0, -1, -1, -1, 0 });

            for (int y = 0; y < prc.Height; y++)
            {
                float *ip  = pixels + y * stride;
                float *ipe = ip + prc.Width * 4 - Vector <float> .Count;

                while (ip <= ipe)
                {
                    var   vi = Unsafe.Read <Vector <float> >(ip);
                    float ia0 = vi[3], ia1 = Vector <float> .Count == 8 ? vi[7] : ia0;

                    if (ia0 == 0 && ia1 == 0)
                    {
                        Unsafe.Write(ip, vmat);
                    }
                    else if (ia0 < 1f || ia1 < 1f)
                    {
                        var vpa = Vector.ConditionalSelect(vm0, new Vector <float>(ia0), new Vector <float>(ia1));
                        var vma = v1 - vpa;

                        var vr = vi + vmat * vma;
                        var vo = Vector.ConditionalSelect(vm1, vr, v1);
                        Unsafe.Write(ip, vo);
                    }

                    ip += Vector <float> .Count;
                }

                ipe += Vector <float> .Count;
                while (ip < ipe)
                {
                    float ib = ip[0], ig = ip[1], ir = ip[2], ia = ip[3], ma = 1f - ia;

                    ib += mbl * ma;
                    ig += mgl * ma;
                    ir += mrl * ma;

                    ip[0] = ib;
                    ip[1] = ig;
                    ip[2] = ir;
                    ip[3] = 1f;

                    ip += 4;
                }
            }
        }
예제 #9
0
 public PixelSourceFromIWICBitmapSource(IWICBitmapSource source, string name, bool profile = true) : base()
 {
     realSource = source;
     sourceRect = new WICRect();
     sourceName = profile ? name : $"{name} (nonprofiling)";
     WicSource  = profile ? this.AsIWICBitmapSource() : source;
     Format     = PixelFormat.Cache[source.GetPixelFormat()];
     source.GetSize(out uint width, out uint height);
     Width  = width;
     Height = height;
 }
예제 #10
0
        unsafe private void applyMatteCompressed(WICRect prc, byte *pixels, int stride, bool premul)
        {
            const byte maxalpha = byte.MaxValue;

            fixed(ushort *igtstart = LookupTables.InverseGammaUQ15, atstart = LookupTables.AlphaUQ15)
            fixed(byte *gtstart = LookupTables.Gamma)
            {
                byte *  gt = gtstart;
                ushort *igt = igtstart, at = atstart;

                ushort mrl = igt[maskRed], mgl = igt[maskGreen], mbl = igt[maskBlue];

                for (int y = 0; y < prc.Height; y++)
                {
                    byte *ip  = pixels + y * stride;
                    byte *ipe = ip + stride;

                    while (ip < ipe)
                    {
                        int alpha = ip[3];
                        if (alpha == 0)
                        {
                            ip[0] = maskBlue;
                            ip[1] = maskGreen;
                            ip[2] = maskRed;
                            ip[3] = maxalpha;
                        }
                        else if (alpha < maxalpha)
                        {
                            int ia = at[alpha], ma = UQ15One - ia;
                            int ib = igt[ip[0]];
                            int ig = igt[ip[1]];
                            int ir = igt[ip[2]];
                            if (premul)
                            {
                                ia = UQ15One;
                            }

                            ib = UnscaleToUQ15(ib * ia + mbl * ma);
                            ig = UnscaleToUQ15(ig * ia + mgl * ma);
                            ir = UnscaleToUQ15(ir * ia + mrl * ma);

                            ip[0] = gt[ib];
                            ip[1] = gt[ig];
                            ip[2] = gt[ir];
                            ip[3] = maxalpha;
                        }

                        ip += 4;
                    }
                }
            }
        }
예제 #11
0
        public static void FillBlobFromBitmapSource(this IWICBitmapSource bitmap, IntPtr blob, int bufferStride, int bufferSize)
        {
            if (bitmap == null)
            {
                throw new ArgumentNullException("bitmap");
            }
            WICRect wicrect = default(WICRect);

            bitmap.GetSize(out wicrect.Width, out wicrect.Height);
            using (PinHelper pinHelper = new PinHelper(blob))
            {
                bitmap.CopyPixels(ref wicrect, bufferStride, bufferSize, pinHelper.Addr);
            }
        }
예제 #12
0
        unsafe private void loadBuffer(byte *pBuffY, byte *pBuffC, WICRect rect)
        {
            var planes = new WICBitmapPlane[2];

            planes[0].Format       = sourceY.GetPixelFormat();
            planes[1].Format       = sourceC.GetPixelFormat();
            planes[0].cbStride     = (uint)strideY;
            planes[1].cbStride     = (uint)strideC;
            planes[0].cbBufferSize = (uint)lineBuffY.Count;
            planes[1].cbBufferSize = (uint)lineBuffC.Count;
            planes[0].pbBuffer     = (IntPtr)pBuffY;
            planes[1].pbBuffer     = (IntPtr)pBuffC;

            sourceTransform.CopyPixels(rect, scaledWidth, scaledHeight, sourceTransformOptions, WICPlanarOptions.WICPlanarOptionsDefault, planes, 2);
        }
예제 #13
0
        public void Clip(int left, int top, int width, int height)
        {
            var rect = new WICRect();

            rect.X      = left;
            rect.Y      = top;
            rect.Width  = width;
            rect.Height = height;

            var clip = WICImagingFactory.CreateBitmapClipper();

            clip.Object.Initialize(_comObject.Object, ref rect).ThrowOnError();
            _comObject?.Dispose();
            _comObject = clip;
        }
예제 #14
0
        unsafe public override void CopyPixels(WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer)
        {
            Source.CopyPixels(prc, cbStride, cbBufferSize, pbBuffer);

            if (Format == Consts.GUID_WICPixelFormat64bppBGRA)
            {
                applyMatteLinear(prc, (ushort *)pbBuffer, (int)(cbStride / sizeof(ushort)));
            }
            else
            {
                fixed(ushort *igtstart = LookupTables.InverseGamma, atstart = LookupTables.Alpha)
                fixed(byte *gtstart = LookupTables.Gamma)
                applyMatteGamma(prc, igtstart, gtstart, atstart, (byte *)pbBuffer, (int)cbStride);
            }
        }
예제 #15
0
        unsafe private void applyMatteLinear(WICRect prc, ushort *pixels, int stride, bool premul)
        {
            const ushort maxalpha = UQ15One;
            var          igt = LookupTables.InverseGammaUQ15;
            ushort       mrl = igt[maskRed], mgl = igt[maskGreen], mbl = igt[maskBlue];

            for (int y = 0; y < prc.Height; y++)
            {
                ushort *ip  = pixels + y * stride;
                ushort *ipe = ip + prc.Width * 4;

                while (ip < ipe)
                {
                    int alpha = ip[3];
                    if (alpha == 0)
                    {
                        ip[0] = mbl;
                        ip[1] = mgl;
                        ip[2] = mrl;
                        ip[3] = maxalpha;
                    }
                    else if (alpha < maxalpha)
                    {
                        int    ia = alpha, ma = maxalpha - ia;
                        ushort ib = ip[0];
                        ushort ig = ip[1];
                        ushort ir = ip[2];
                        if (premul)
                        {
                            ia = UQ15One;
                        }

                        ib = UnFixToUQ15(ib * ia + mbl * ma);
                        ig = UnFixToUQ15(ig * ia + mgl * ma);
                        ir = UnFixToUQ15(ir * ia + mrl * ma);

                        ip[0] = ib;
                        ip[1] = ig;
                        ip[2] = ir;
                        ip[3] = maxalpha;
                    }

                    ip += 4;
                }
            }
        }
예제 #16
0
        public WicConvolution8bpc(IWICBitmapSource source, KernelMap mapx, KernelMap mapy, bool bufferSource = false) : base(source)
        {
            BufferSource = bufferSource;
            XMap         = mapx;
            YMap         = mapy;
            XMapAlpha    = mapx.MakeAlphaMap();
            YMapAlpha    = mapy.MakeAlphaMap();
            OutWidth     = (uint)mapx.OutPixelCount;
            OutHeight    = (uint)mapy.OutPixelCount;
            SourceRect   = new WICRect()
            {
                Width = (int)Width, Height = 1
            };

            if (Format == Consts.GUID_WICPixelFormat32bppPBGRA)
            {
                Processor = new ConvolverBgra8bpc();
            }
            else if (Format == Consts.GUID_WICPixelFormat32bppBGRA)
            {
                Processor = new ConvolverBgra8bpc();
            }
            else if (Format == Consts.GUID_WICPixelFormat24bppBGR)
            {
                Processor = new ConvolverBgr8bpc();
            }
            else if (Format == Consts.GUID_WICPixelFormat8bppGray)
            {
                Processor = new ConvolverGrey8bpc();
            }
            else if (Format == Consts.GUID_WICPixelFormat8bppY)
            {
                Processor = new ConvolverGrey8bpc();
            }
            else
            {
                throw new NotSupportedException("Unsupported pixel format");
            }

            Stride   /= sizeof(byte);
            IntStride = (int)(mapy.SampleCount * Channels);

            LineBuff     = new byte[(bufferSource ? mapy.SampleCount : 1) * Stride];
            IntBuff      = new int[OutWidth * IntStride];
            IntStartLine = -mapy.SampleCount;
        }
예제 #17
0
        unsafe public override void CopyPixels(WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer)
        {
            Source.CopyPixels(prc, cbStride, cbBufferSize, pbBuffer);

            if (Format == PixelFormat.Pbgra128BppLinearFloat)
            {
                applyMatteLinearFloat(prc, (float *)pbBuffer, (int)(cbStride / sizeof(float)));
            }
            else if (Format == PixelFormat.Bgra64BppLinearUQ15 || Format == PixelFormat.Pbgra64BppLinearUQ15)
            {
                applyMatteLinear(prc, (ushort *)pbBuffer, (int)(cbStride / sizeof(ushort)), Format.AlphaRepresentation == PixelAlphaRepresentation.Associated);
            }
            else if (Format.FormatGuid == Consts.GUID_WICPixelFormat32bppBGRA || Format.FormatGuid == Consts.GUID_WICPixelFormat32bppPBGRA)
            {
                applyMatteCompressed(prc, (byte *)pbBuffer, (int)cbStride, Format.AlphaRepresentation == PixelAlphaRepresentation.Associated);
            }
        }
예제 #18
0
        /// <summary>
        /// Adds padding to a bitmap, optionally cropping it at the same time.
        /// </summary>
        /// <param name="s"></param>
        /// <param name="left"></param>
        /// <param name="top"></param>
        /// <param name="right"></param>
        /// <param name="bottom"></param>
        /// <param name="bgcolor"></param>
        /// <param name="crop"></param>
        public WicBitmapPadder(IWICBitmapSource s, int left, int top, int right, int bottom, byte[] bgcolor, WICRect crop)
        {
            this.s       = s;
            this.left    = left;
            this.right   = right;
            this.bottom  = bottom;
            this.top     = top;
            this.bgcolor = bgcolor;
            this.crop    = crop;

            Guid pf;

            s.GetPixelFormat(out pf);
            if (bgcolor.Length != ConversionUtils.BytesPerPixel(pf))
            {
                throw new ArgumentException("bgcolor length must match the format bytes per pixel");
            }
        }
예제 #19
0
        unsafe private void applyMatteGamma(WICRect prc, ushort *igtstart, byte *gtstart, ushort *atstart, byte *pixels, int stride)
        {
            const byte maxalpha = byte.MaxValue;

            byte *  gt = gtstart;
            ushort *igt = igtstart, at = atstart;

            for (int y = 0; y < prc.Height; y++)
            {
                byte *ip  = pixels + y * stride;
                byte *ipe = ip + prc.Width * Channels;

                while (ip < ipe)
                {
                    int alpha = ip[3];
                    if (alpha == 0)
                    {
                        ip[0] = MaskBlue;
                        ip[1] = MaskGreen;
                        ip[2] = MaskRed;
                        ip[3] = maxalpha;
                    }
                    else if (alpha < maxalpha)
                    {
                        int ia = at[alpha], ma = IntScale - ia;
                        int ib = igt[ip[0]];
                        int ig = igt[ip[1]];
                        int ir = igt[ip[2]];

                        ib = UnscaleToUInt15(ib * ia + MaskBlueLinear * ma);
                        ig = UnscaleToUInt15(ig * ia + MaskGreenLinear * ma);
                        ir = UnscaleToUInt15(ir * ia + MaskRedLinear * ma);

                        ip[0] = gt[ib];
                        ip[1] = gt[ig];
                        ip[2] = gt[ir];
                        ip[3] = maxalpha;
                    }

                    ip += 4;
                }
            }
        }
예제 #20
0
        unsafe protected override void CopyPixelsInternal(WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer)
        {
            fixed(byte *bstart = &LineBuff.Array[0], wstart = &WorkBuff.Array[0], tstart = &IntBuff.Array[0])
            fixed(byte *mapxstart = &XMap.Map.Array[0], mapystart = &YMap.Map.Array[0])
            {
                int oh = prc.Height, ow = prc.Width, ox = prc.X, oy = prc.Y;
                int smapy = YMap.Samples, chan = YMap.Channels;

                for (int y = 0; y < oh; y++)
                {
                    int *pmapy = (int *)mapystart + ((oy + y) * (smapy * chan + 1));
                    int  iy    = *pmapy++;
                    LoadBuffer(bstart, wstart, tstart, mapxstart, iy);

                    byte *op = (byte *)pbBuffer + y * cbStride;
                    ConvolveLine(bstart, wstart, tstart, op, (byte *)pmapy, smapy, ox, oy + y, ow);
                }
            }
        }
예제 #21
0
        public static void UpdateGifAnimationContext(WicGifContainer cont, ComPtr <IWICBitmapSource> src, ComPtr <IWICMetadataQueryReader> meta)
        {
            Debug.Assert(cont.AnimationContext is not null);
            var anictx = cont.AnimationContext;

            const int bytesPerPixel = 4;

            var finfo = GetGifFrameInfo(cont, src, meta);
            var fbuff = anictx.FrameBufferSource ??= new FrameBufferSource(cont.ScreenWidth, cont.ScreenHeight, PixelFormat.Bgra32Bpp);
            var bspan = fbuff.Span;

            fbuff.ResumeTiming();

            // Most GIF viewers clear the background to transparent instead of the background color when the next frame has transparency
            bool ftrans = meta.GetValueOrDefault <bool>(Wic.Metadata.Gif.TransparencyFlag);

            if (!finfo.FullScreen && anictx.LastDisposal == GifDisposalMethod.RestoreBackground)
            {
                MemoryMarshal.Cast <byte, uint>(bspan).Fill(ftrans ? 0 : cont.BackgroundColor);
            }

            // Similarly, they overwrite a background color with transparent pixels but overlay instead when the previous frame is preserved
            var fspan = bspan.Slice(finfo.Top * fbuff.Stride + finfo.Left * bytesPerPixel);

            fixed(byte *buff = fspan)
            {
                if (!ftrans || anictx.LastDisposal == GifDisposalMethod.RestoreBackground)
                {
                    var rect = new WICRect {
                        Width = finfo.Width, Height = finfo.Height
                    };
                    HRESULT.Check(src.Get()->CopyPixels(&rect, (uint)fbuff.Stride, (uint)fspan.Length, buff));
                }
                else
                {
                    using var overlay = new OverlayTransform(fbuff, src.AsPixelSource(null, nameof(IWICBitmapFrameDecode), false), finfo.Left, finfo.Top, true, true);
                    overlay.CopyPixels(new PixelArea(finfo.Left, finfo.Top, finfo.Width, finfo.Height), fbuff.Stride, fspan.Length, (IntPtr)buff);
                }
            }

            fbuff.PauseTiming();
        }
예제 #22
0
        public void CopyPixels(ref WICRect prc, uint cbStride, uint cbBufferSize, byte[] pbBuffer)
        {
            //Log.Trace($"CopyPixels called: ({prc.X} {prc.Y} {prc.Width} {prc.Height}) Stride: {cbStride}, Size: {cbBufferSize}");

            try
            {
                //Log.Trace($"CopyPixels rgbmap {rgbmap.Width}, {rgbmap.Height}");
                CopyBGRA(ref prc, cbStride, cbBufferSize, pbBuffer);
                if (prc.Y + prc.Height == rgbmap.Height)
                {
                    rgbmap.Dispose();
                }
                //Log.Trace("CopyPixels finished");
            }
            catch (Exception e)
            {
                Log.Error("CopyPixels failed: " + e);
                throw;
            }
        }
예제 #23
0
        protected override bool ProcessFrameDecode(MainForm form, IWICBitmapFrameDecode frame, DataEntry[] de, object tag)
        {
            CheckGetColorContexts(form, de, frame.GetColorContexts);

            CheckGetBitmapSource(form, de, frame.GetThumbnail, WinCodecError.WINCODEC_ERR_CODECNOTHUMBNAIL);

            uint width;
            uint height;

            frame.GetSize(out width, out height);

            Guid pixelFormat;

            frame.GetPixelFormat(out pixelFormat);


            uint stride = (PixelFormatInfoRule.GetBitPerPixel(pixelFormat) * width + 7) / 8;

            byte[]  buffer = new byte[stride * height];
            WICRect rect   = new WICRect();

            rect.Height = (int)Math.Min(height, int.MaxValue);
            rect.Width  = (int)Math.Min(width, int.MaxValue);
            try
            {
                frame.CopyPixels(rect, stride, stride * height, buffer);
                try
                {
                    frame.CopyPixels(null, stride, stride * height, buffer);
                }
                catch (Exception e)
                {
                    form.Add(this, e.TargetSite.ToString(Resources._0_Failed, "NULL"), de, new DataEntry(e));
                }
            }
            catch
            {
            }

            return(true);
        }
예제 #24
0
        unsafe private void applyMatteLinear(WICRect prc, ushort *pixels, int stride)
        {
            const ushort maxalpha = IntScale;
            ushort       mrl = MaskRedLinear, mgl = MaskGreenLinear, mbl = MaskBlueLinear;

            for (int y = 0; y < prc.Height; y++)
            {
                ushort *ip  = pixels + y * stride;
                ushort *ipe = ip + prc.Width * Channels;

                while (ip < ipe)
                {
                    int alpha = ip[3];
                    if (alpha == 0)
                    {
                        ip[0] = mbl;
                        ip[1] = mgl;
                        ip[2] = mrl;
                        ip[3] = maxalpha;
                    }
                    else if (alpha < IntScale)
                    {
                        int    ia = alpha, ma = maxalpha - ia;
                        ushort ib = ip[0];
                        ushort ig = ip[1];
                        ushort ir = ip[2];

                        ib = UnscaleToUInt15(ib * ia + mbl * ma);
                        ig = UnscaleToUInt15(ig * ia + mgl * ma);
                        ir = UnscaleToUInt15(ir * ia + mrl * ma);

                        ip[0] = ib;
                        ip[1] = ig;
                        ip[2] = ir;
                        ip[3] = maxalpha;
                    }

                    ip += 4;
                }
            }
        }
예제 #25
0
        public static void FillBlobFromBitmapSource(this IWICBitmapSource bitmap, Array blob)
        {
            if (bitmap == null)
            {
                throw new ArgumentNullException("bitmap");
            }
            if (blob == null)
            {
                throw new ArgumentNullException("blob");
            }
            WICRect wicrect = default(WICRect);

            bitmap.GetSize(out wicrect.Width, out wicrect.Height);
            int arrayStride     = WicUtility.GetArrayStride(blob, wicrect.Width, wicrect.Height);
            int arrayBufferSize = WicUtility.GetArrayBufferSize(blob);

            using (PinHelper pinHelper = new PinHelper(blob))
            {
                bitmap.CopyPixels(ref wicrect, arrayStride, arrayBufferSize, pinHelper.Addr);
            }
        }
예제 #26
0
        unsafe public override void CopyPixels(WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer)
        {
            fixed(byte *bstart = LineBuff)
            fixed(int *mapystart = YMap.Map, mapxstart = XMap.Map, mapxastart = XMapAlpha.Map, mapyastart = YMapAlpha.Map)
            fixed(int *tstart    = IntBuff)
            {
                int oh = prc.Height, ow = prc.Width, ox = prc.X, oy = prc.Y;
                int smapy = YMap.SampleCount;

                for (int y = 0; y < oh; y++)
                {
                    int *pmapy  = mapystart + ((oy + y) * (smapy + 1));
                    int *pmapya = mapyastart + ((oy + y) * (smapy + 1)) + 1;
                    int  iy     = *pmapy++;
                    LoadBuffer(bstart, tstart, mapxstart, mapxastart, iy);

                    void *op = (byte *)pbBuffer + y * cbStride;
                    ConvolveLine(bstart, tstart, (byte *)op, pmapy, pmapya, smapy, ox, oy + y, ow);
                }
            }
        }
예제 #27
0
        public void CenterClip(int?width, int?height)
        {
            if (!width.HasValue && !height.HasValue)
            {
                return;
            }

            var rect = new WICRect();
            int w    = Width;
            int h    = Height;

            if (width.HasValue && width.Value < w)
            {
                rect.Width = width.Value;
                rect.X     = (w - width.Value) / 2;
            }
            else
            {
                rect.Width = w;
                rect.X     = 0;
            }

            if (height.HasValue && height.Value < h)
            {
                rect.Height = height.Value;
                rect.Y      = (h - height.Value) / 2;
            }
            else
            {
                rect.Height = h;
                rect.Y      = 0;
            }

            var clip = WICImagingFactory.CreateBitmapClipper();

            clip.Object.Initialize(_comObject.Object, ref rect).ThrowOnError();
            _comObject?.Dispose();
            _comObject = clip;
        }
예제 #28
0
 public void CopyPixels([In] ref WICRect prc, [In] uint uiWidth, [In] uint uiHeight, Guid dstFormat, [In] WICBitmapTransformOptions dstTransform, [In] uint nStride, [In] uint cbBufferSize, byte[] pbBuffer)
 {
     try
     {
         Log.Trace($"Trans CopyPixels called");
         Log.Trace($"Trans CopyPixels called: {uiWidth}, {uiHeight} {dstFormat}");
         if (dstFormat == GUID_WICPixelFormat32bppBGRA)
         {
             CopyBGRA(ref prc, nStride, cbBufferSize, pbBuffer);
         }
         if (prc.Y + prc.Height == rgbmap.Height)
         {
             rgbmap.Dispose();
         }
         Log.Trace("CopyPixels finished");
     }
     catch (Exception e)
     {
         Log.Error("CopyPixels failed: " + e);
         throw;
     }
 }
        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);
        }
예제 #30
0
        static void Main(string [] args)
        {
            IWICImagingFactory factory = new WICImagingFactory();

            factory.CreateDecoder(ContainerFormats.Png, Vendors.Microsoft, out IWICBitmapDecoder decoder);
            using (Stream inputStream = new FileStream("Test.png", FileMode.Open))
            {
                decoder.Initialize(inputStream.AsIStream(), WICDecodeOptions.MetadataCacheOnDemand);
                decoder.GetFrame(0, out IWICBitmapFrameDecode bitmapFrame);

                bitmapFrame.GetSize(out uint width, out uint height);
                bitmapFrame.GetResolution(out double dpiX, out double dpiY);
                Console.WriteLine($"Width: {width}, Height: {height}, DPI: {dpiX}x{dpiY}");

                factory.CreateFormatConverter(out IWICFormatConverter formatConverter);
                formatConverter.Initialize(bitmapFrame, PixelFormats.PixelFormat32bppBGRA, WICBitmapDitherType.None, null, 1, WICBitmapPaletteType.Custom);

                using (Stream outputStream = new FileStream("Output.png", FileMode.Create))
                {
                    factory.CreateEncoder(ContainerFormats.Png, Vendors.Microsoft, out IWICBitmapEncoder encoder);

                    encoder.Initialize(outputStream.AsIStream(), WICBitmapEncoderCacheOption.NoCache);
                    encoder.CreateNewFrame(out IWICBitmapFrameEncode frameEncode, out IPropertyBag2 encoderOptions);

                    frameEncode.Initialize(encoderOptions);
                    frameEncode.SetPixelFormat(PixelFormats.PixelFormat32bppBGRA);
                    frameEncode.SetSize(width, height);
                    frameEncode.SetResolution(dpiX, dpiY);

                    WICRect rect = new WICRect(0, 0, ( int )width, ( int )height);
                    frameEncode.WriteSource(formatConverter, ref rect);

                    frameEncode.Commit();

                    encoder.Commit();
                }
            }
        }