Esempio n. 1
0
        private unsafe void DoCopyRaw(int sourceStride, int targetStride, byte *sourceOrigin, byte *targetOrigin)
        {
            // Sequential processing
            if (SourceRectangle.Width < parallelThreshold)
            {
                context.Progress?.New(DrawingOperation.ProcessingPixels, SourceRectangle.Height);
                byte *pSrc = sourceOrigin + SourceRectangle.Y * sourceStride + SourceRectangle.X;
                byte *pDst = targetOrigin + TargetRectangle.Y * targetStride + TargetRectangle.X;
                for (int y = 0; y < SourceRectangle.Height; y++)
                {
                    if (context.IsCancellationRequested)
                    {
                        return;
                    }
                    MemoryHelper.CopyMemory(pSrc, pDst, SourceRectangle.Width);
                    pSrc += sourceStride;
                    pDst += targetStride;
                    context.Progress?.Increment();
                }

                return;
            }

            // Parallel processing
            Point sourceLocation = SourceRectangle.Location;
            Point targetLocation = TargetRectangle.Location;
            int   width          = SourceRectangle.Width;

            ParallelHelper.For(context, DrawingOperation.ProcessingPixels, 0, SourceRectangle.Height, y =>
            {
                byte *pSrc = sourceOrigin + (y + sourceLocation.Y) * sourceStride + sourceLocation.X;
                byte *pDst = targetOrigin + (y + targetLocation.Y) * targetStride + targetLocation.X;
                MemoryHelper.CopyMemory(pSrc, pDst, width);
            });
        }
        public void Test_ParallelHelper_ParameterName_ThrowArgumentOutOfRangeExceptionForStartGreaterThanEnd()
        {
            try
            {
                ParallelHelper.For <DummyAction>(1, 0);
            }
            catch (ArgumentOutOfRangeException e) when(e.GetType() == typeof(ArgumentOutOfRangeException))
            {
                var name = (
                    from method in typeof(ParallelHelper).GetMethods()
                    where
                    method.Name == nameof(ParallelHelper.For) &&
                    method.IsGenericMethodDefinition
                    let typeParams = method.GetGenericArguments()
                                     let normalParams = method.GetParameters()
                                                        where
                                                        typeParams.Length == 1 &&
                                                        normalParams.Length == 2 &&
                                                        normalParams.All(p => p.ParameterType == typeof(int))
                                                        select normalParams[0].Name).Single();

                Assert.AreEqual(e.ParamName, name);

                return;
            }

            Assert.Fail("Failed to raise correct exception");
        }
Esempio n. 3
0
        private void PerformCopyDirectPremultiplied()
        {
            // Sequential processing
            if (SourceRectangle.Width < parallelThreshold)
            {
                context.Progress?.New(DrawingOperation.ProcessingPixels, SourceRectangle.Height);
                IBitmapDataRowInternal rowSrc = Source.DoGetRow(SourceRectangle.Y);
                IBitmapDataRowInternal rowDst = Target.DoGetRow(TargetRectangle.Y);
                for (int y = 0; y < SourceRectangle.Height; y++)
                {
                    if (context.IsCancellationRequested)
                    {
                        return;
                    }
                    for (int x = 0; x < SourceRectangle.Width; x++)
                    {
                        rowDst.DoSetColor32Premultiplied(x + TargetRectangle.X, rowSrc.DoGetColor32Premultiplied(x + SourceRectangle.X));
                    }
                    rowSrc.MoveNextRow();
                    rowDst.MoveNextRow();
                    context.Progress?.Increment();
                }

                return;
            }

            // Parallel processing
            IBitmapDataInternal source = Source;
            IBitmapDataInternal target = Target;
            Point sourceLocation       = SourceRectangle.Location;
            Point targetLocation       = TargetRectangle.Location;
            int   sourceWidth          = SourceRectangle.Width;

            ParallelHelper.For(context, DrawingOperation.ProcessingPixels, 0, SourceRectangle.Height, y =>
            {
                IBitmapDataRowInternal rowSrc = source.DoGetRow(sourceLocation.Y + y);
                IBitmapDataRowInternal rowDst = target.DoGetRow(targetLocation.Y + y);
                int offsetSrc = sourceLocation.X;
                int offsetDst = targetLocation.X;
                int width     = sourceWidth;
                for (int x = 0; x < width; x++)
                {
                    rowDst.DoSetColor32Premultiplied(x + offsetDst, rowSrc.DoGetColor32Premultiplied(x + offsetSrc));
                }
            });
        }
Esempio n. 4
0
        internal void PerformCopyWithQuantizer(IQuantizingSession quantizingSession, bool skipTransparent)
        {
            // Sequential processing
            if (SourceRectangle.Width < parallelThreshold >> quantizingScale)
            {
                context.Progress?.New(DrawingOperation.ProcessingPixels, SourceRectangle.Height);
                IBitmapDataRowInternal rowSrc = Source.DoGetRow(SourceRectangle.Y);
                IBitmapDataRowInternal rowDst = Target.DoGetRow(TargetRectangle.Y);
                byte alphaThreshold           = quantizingSession.AlphaThreshold;
                for (int y = 0; y < SourceRectangle.Height; y++)
                {
                    if (context.IsCancellationRequested)
                    {
                        return;
                    }
                    for (int x = 0; x < SourceRectangle.Width; x++)
                    {
                        Color32 colorSrc = rowSrc.DoGetColor32(x + SourceRectangle.X);
                        if (skipTransparent && colorSrc.A < alphaThreshold)
                        {
                            continue;
                        }

                        rowDst.DoSetColor32(x + TargetRectangle.X, quantizingSession.GetQuantizedColor(colorSrc));
                    }

                    rowSrc.MoveNextRow();
                    rowDst.MoveNextRow();
                    context.Progress?.Increment();
                }

                return;
            }

            IBitmapDataInternal source = Source;
            IBitmapDataInternal target = Target;
            Point sourceLocation       = SourceRectangle.Location;
            Point targetLocation       = TargetRectangle.Location;
            int   sourceWidth          = SourceRectangle.Width;

            ParallelHelper.For(context, DrawingOperation.ProcessingPixels, 0, SourceRectangle.Height, y =>
            {
                IQuantizingSession session    = quantizingSession;
                IBitmapDataRowInternal rowSrc = source.DoGetRow(sourceLocation.Y + y);
                IBitmapDataRowInternal rowDst = target.DoGetRow(targetLocation.Y + y);
                int offsetSrc       = sourceLocation.X;
                int offsetDst       = targetLocation.X;
                int width           = sourceWidth;
                byte alphaThreshold = session.AlphaThreshold;
                bool skip           = skipTransparent;
                for (int x = 0; x < width; x++)
                {
                    Color32 colorSrc = rowSrc.DoGetColor32(x + offsetSrc);
                    if (skip && colorSrc.A < alphaThreshold)
                    {
                        continue;
                    }

                    rowDst.DoSetColor32(x + offsetDst, session.GetQuantizedColor(colorSrc));
                }
            });
        }
Esempio n. 5
0
        private void PerformDrawWithDithering(IQuantizingSession quantizingSession, IDitheringSession ditheringSession)
        {
            IBitmapDataInternal source = Source;
            IBitmapDataInternal target = Target;
            Point sourceLocation       = SourceRectangle.Location;
            Point targetLocation       = TargetRectangle.Location;
            int   sourceWidth          = SourceRectangle.Width;

            // Sequential processing
            if (ditheringSession.IsSequential || SourceRectangle.Width < parallelThreshold >> ditheringScale)
            {
                context.Progress?.New(DrawingOperation.ProcessingPixels, SourceRectangle.Height);
                for (int y = 0; y < SourceRectangle.Height; y++)
                {
                    if (context.IsCancellationRequested)
                    {
                        return;
                    }
                    ProcessRow(y);
                    context.Progress?.Increment();
                }

                return;
            }

            // Parallel processing
            ParallelHelper.For(context, DrawingOperation.ProcessingPixels, 0, SourceRectangle.Height, ProcessRow);

            #region Local Methods

            void ProcessRow(int y)
            {
                IDitheringSession      session = ditheringSession;
                IBitmapDataRowInternal rowSrc  = source.DoGetRow(sourceLocation.Y + y);
                IBitmapDataRowInternal rowDst  = target.DoGetRow(targetLocation.Y + y);
                int  offsetSrc      = sourceLocation.X;
                int  offsetDst      = targetLocation.X;
                byte alphaThreshold = quantizingSession.AlphaThreshold;
                int  width          = sourceWidth;

                for (int x = 0; x < width; x++)
                {
                    Color32 colorSrc = rowSrc.DoGetColor32(x + offsetSrc);

                    // fully solid source: overwrite
                    if (colorSrc.A == Byte.MaxValue)
                    {
                        rowDst.DoSetColor32(x + offsetDst, session.GetDitheredColor(colorSrc, x, y));
                        continue;
                    }

                    // fully transparent source: skip
                    if (colorSrc.A == 0)
                    {
                        continue;
                    }

                    // source here has a partial transparency: we need to read the target color
                    int     pos      = x + offsetDst;
                    Color32 colorDst = rowDst.DoGetColor32(pos);

                    // non-transparent target: blending
                    if (colorDst.A != 0)
                    {
                        colorSrc = colorDst.A == Byte.MaxValue
                                   // target pixel is fully solid: simple blending
                            ? colorSrc.BlendWithBackground(colorDst)
                                   // both source and target pixels are partially transparent: complex blending
                            : colorSrc.BlendWith(colorDst);
                    }

                    // overwriting target color only if blended color has high enough alpha
                    if (colorSrc.A < alphaThreshold)
                    {
                        continue;
                    }

                    rowDst.DoSetColor32(pos, session.GetDitheredColor(colorSrc, x, y));
                }
            }

            #endregion
        }
Esempio n. 6
0
        internal void PerformDrawDirect()
        {
            IBitmapDataInternal source = Source;
            IBitmapDataInternal target = Target;
            Point sourceLocation       = SourceRectangle.Location;
            Point targetLocation       = TargetRectangle.Location;
            int   sourceWidth          = SourceRectangle.Width;

            // Sequential processing
            if (SourceRectangle.Width < parallelThreshold)
            {
                if (Target.IsFastPremultiplied())
                {
                    context.Progress?.New(DrawingOperation.ProcessingPixels, SourceRectangle.Height);
                    for (int y = 0; y < SourceRectangle.Height; y++)
                    {
                        if (context.IsCancellationRequested)
                        {
                            return;
                        }
                        ProcessRowPremultiplied(y);
                        context.Progress?.Increment();
                    }
                }
                else
                {
                    context.Progress?.New(DrawingOperation.ProcessingPixels, SourceRectangle.Height);
                    for (int y = 0; y < SourceRectangle.Height; y++)
                    {
                        if (context.IsCancellationRequested)
                        {
                            return;
                        }
                        ProcessRowStraight(y);
                        context.Progress?.Increment();
                    }
                }

                return;
            }

            // Parallel processing
            Action <int> processRow = Target.IsFastPremultiplied()
                ? ProcessRowPremultiplied
                : (Action <int>)ProcessRowStraight;

            ParallelHelper.For(context, DrawingOperation.ProcessingPixels, 0, SourceRectangle.Height, processRow);

            #region Local Methods

            void ProcessRowStraight(int y)
            {
                IBitmapDataRowInternal rowSrc = source.DoGetRow(sourceLocation.Y + y);
                IBitmapDataRowInternal rowDst = target.DoGetRow(targetLocation.Y + y);
                int  offsetSrc      = sourceLocation.X;
                int  offsetDst      = targetLocation.X;
                byte alphaThreshold = target.AlphaThreshold;
                int  width          = sourceWidth;

                for (int x = 0; x < width; x++)
                {
                    Color32 colorSrc = rowSrc.DoGetColor32(x + offsetSrc);

                    // fully solid source: overwrite
                    if (colorSrc.A == Byte.MaxValue)
                    {
                        rowDst.DoSetColor32(x + offsetDst, colorSrc);
                        continue;
                    }

                    // fully transparent source: skip
                    if (colorSrc.A == 0)
                    {
                        continue;
                    }

                    // source here has a partial transparency: we need to read the target color
                    int     pos      = x + offsetDst;
                    Color32 colorDst = rowDst.DoGetColor32(pos);

                    // non-transparent target: blending
                    if (colorDst.A != 0)
                    {
                        colorSrc = colorDst.A == Byte.MaxValue
                                   // target pixel is fully solid: simple blending
                            ? colorSrc.BlendWithBackground(colorDst)
                                   // both source and target pixels are partially transparent: complex blending
                            : colorSrc.BlendWith(colorDst);
                    }

                    // overwriting target color only if blended color has high enough alpha
                    if (colorSrc.A < alphaThreshold)
                    {
                        continue;
                    }

                    rowDst.DoSetColor32(pos, colorSrc);
                }
            }

            void ProcessRowPremultiplied(int y)
            {
                IBitmapDataRowInternal rowSrc = source.DoGetRow(sourceLocation.Y + y);
                IBitmapDataRowInternal rowDst = target.DoGetRow(targetLocation.Y + y);
                int offsetSrc = sourceLocation.X;
                int offsetDst = targetLocation.X;
                int width     = sourceWidth;

                for (int x = 0; x < width; x++)
                {
                    Color32 colorSrc = rowSrc.DoGetColor32Premultiplied(x + offsetSrc);

                    // fully solid source: overwrite
                    if (colorSrc.A == Byte.MaxValue)
                    {
                        rowDst.DoSetColor32Premultiplied(x + offsetDst, colorSrc);
                        continue;
                    }

                    // fully transparent source: skip
                    if (colorSrc.A == 0)
                    {
                        continue;
                    }

                    // source here has a partial transparency: we need to read the target color
                    int     pos      = x + offsetDst;
                    Color32 colorDst = rowDst.DoGetColor32Premultiplied(pos);

                    // non-transparent target: blending
                    if (colorDst.A != 0)
                    {
                        colorSrc = colorSrc.BlendWithPremultiplied(colorDst);
                    }

                    rowDst.DoSetColor32Premultiplied(pos, colorSrc);
                }
            }

            #endregion
        }
Esempio n. 7
0
        internal void PerformCopyWithDithering(IQuantizingSession quantizingSession, IDitheringSession ditheringSession, bool skipTransparent)
        {
            // Sequential processing
            if (ditheringSession.IsSequential || SourceRectangle.Width < parallelThreshold >> ditheringScale)
            {
                context.Progress?.New(DrawingOperation.ProcessingPixels, SourceRectangle.Height);
                IBitmapDataRowInternal rowSrc = Source.DoGetRow(SourceRectangle.Y);
                IBitmapDataRowInternal rowDst = Target.DoGetRow(TargetRectangle.Y);
                byte alphaThreshold           = quantizingSession.AlphaThreshold;
                for (int y = 0; y < SourceRectangle.Height; y++)
                {
                    if (context.IsCancellationRequested)
                    {
                        return;
                    }

                    // we can pass x, y to the dithering session because if there is an offset it was initialized by a properly clipped rectangle
                    for (int x = 0; x < SourceRectangle.Width; x++)
                    {
                        Color32 colorSrc = rowSrc.DoGetColor32(x + SourceRectangle.X);
                        if (skipTransparent && colorSrc.A < alphaThreshold)
                        {
                            continue;
                        }

                        rowDst.DoSetColor32(x + TargetRectangle.X, ditheringSession.GetDitheredColor(colorSrc, x, y));
                    }

                    rowSrc.MoveNextRow();
                    rowDst.MoveNextRow();
                    context.Progress?.Increment();
                }

                return;
            }

            // Parallel processing
            IBitmapDataInternal source = Source;
            IBitmapDataInternal target = Target;
            Point sourceLocation       = SourceRectangle.Location;
            Point targetLocation       = TargetRectangle.Location;
            int   sourceWidth          = SourceRectangle.Width;

            ParallelHelper.For(context, DrawingOperation.ProcessingPixels, 0, SourceRectangle.Height, y =>
            {
                IDitheringSession session     = ditheringSession;
                IBitmapDataRowInternal rowSrc = source.DoGetRow(sourceLocation.Y + y);
                IBitmapDataRowInternal rowDst = target.DoGetRow(targetLocation.Y + y);
                int offsetSrc       = sourceLocation.X;
                int offsetDst       = targetLocation.X;
                int width           = sourceWidth;
                byte alphaThreshold = quantizingSession.AlphaThreshold;
                bool skip           = skipTransparent;

                // we can pass x, y to the dithering session because if there is an offset it was initialized by a properly clipped rectangle
                for (int x = 0; x < width; x++)
                {
                    Color32 colorSrc = rowSrc.DoGetColor32(x + offsetSrc);
                    if (skip && colorSrc.A < alphaThreshold)
                    {
                        continue;
                    }

                    rowDst.DoSetColor32(x + offsetDst, session.GetDitheredColor(colorSrc, x, y));
                }
            });
        }