public unsafe bool GetUnchecked(int x, int y)
        {
            int  cx   = x / 32;
            int  sx   = x % 32;
            uint mask = surface.GetPointAddressUnchecked(cx, y)->Bgra;

            return(0 != (mask & (1 << sx)));
        }
Ejemplo n.º 2
0
            public unsafe void DrawScansBilinear(object cpuNumberObj)
            {
                int cpuNumber = (int)cpuNumberObj;
                int start     = (this.dstScans.Length * cpuNumber) / Processor.LogicalCpuCount;
                int end       = (this.dstScans.Length * (cpuNumber + 1)) / Processor.LogicalCpuCount;

                PointF[] pts2 = new PointF[1];

                for (int i = start; i < end; ++i)
                {
                    Rectangle dstRect = this.dstScans[i];
                    dstRect.Intersect(dst.Bounds);

                    pts2[0] = new PointF(dstRect.Left, dstRect.Top);

                    this.inverses[cpuNumber].TransformPoints(pts2);

                    pts2[0].X -= this.boundsX;
                    pts2[0].Y -= this.boundsY;

                    // Sometimes pts2 ends up being infintessimally small (1 x 10^-5 or -6) but negative
                    // This throws off GetBilinearSample and it returns transparent colors, which looks horribly wrong.
                    // So we fix that!
                    if (pts2[0].X < 0)
                    {
                        pts2[0].X = 0;
                    }

                    if (pts2[0].Y < 0)
                    {
                        pts2[0].Y = 0;
                    }

                    PointF srcPtRow = pts2[0];

                    for (int dstY = dstRect.Top; dstY < dstRect.Bottom; ++dstY)
                    {
                        PointF srcPtCol = srcPtRow;
                        srcPtRow.X += this.dsxddy;
                        srcPtRow.Y += this.dsyddy;

                        if (dstY >= 0)
                        {
                            int dstX = dstRect.Left;

                            while (dstX < dstRect.Right)
                            {
                                ColorBgra  srcPixel = this.src.GetBilinearSample(srcPtCol.X, srcPtCol.Y);
                                ColorBgra *dstPtr   = dst.GetPointAddressUnchecked(dstX, dstY);
                                *          dstPtr   = srcPixel;

                                srcPtCol.X += this.dsxddx;
                                srcPtCol.Y += this.dsyddx;
                                ++dstX;
                            }
                        }
                    }
                }
            }
Ejemplo n.º 3
0
        protected override unsafe void AddSurfaceRectangleToHistogram(Surface surface, Rectangle rect)
        {
            long[] histogramLuminosity = histogram[0];

            for (int y = rect.Top; y < rect.Bottom; ++y)
            {
                ColorBgra *ptr = surface.GetPointAddressUnchecked(rect.Left, y);
                for (int x = rect.Left; x < rect.Right; ++x)
                {
                    ++histogramLuminosity[ptr->GetIntensityByte()];
                    ++ptr;
                }
            }
        }
Ejemplo n.º 4
0
        protected override unsafe void AddSurfaceRectangleToHistogram(Surface surface, Rectangle rect)
        {
            long[] histogramLuminosity = histogram[0];

            for (int y = rect.Top; y < rect.Bottom; ++y)
            {

                ColorBgra* ptr = surface.GetPointAddressUnchecked(rect.Left, y);
                for (int x = rect.Left; x < rect.Right; ++x)
                {
                    ++histogramLuminosity[ptr->GetIntensityByte()];
                    ++ptr;
                }
            }
        }
Ejemplo n.º 5
0
        protected override unsafe void AddSurfaceRectangleToHistogram(Surface surface, Rectangle rect)
        {
            long[] histogramB = histogram[0];
            long[] histogramG = histogram[1];
            long[] histogramR = histogram[2];

            for (int y = rect.Top; y < rect.Bottom; ++y)
            {
                ColorBgra *ptr = surface.GetPointAddressUnchecked(rect.Left, y);
                for (int x = rect.Left; x < rect.Right; ++x)
                {
                    ++histogramB[ptr->B];
                    ++histogramG[ptr->G];
                    ++histogramR[ptr->R];
                    ++ptr;
                }
            }
        }
Ejemplo n.º 6
0
        protected override unsafe void AddSurfaceRectangleToHistogram(Surface surface, Rectangle rect)
        {
            long[] histogramB = histogram[0];
            long[] histogramG = histogram[1];
            long[] histogramR = histogram[2];

            for (int y = rect.Top; y < rect.Bottom; ++y)
            {
                ColorBgra* ptr = surface.GetPointAddressUnchecked(rect.Left, y);
                for (int x = rect.Left; x < rect.Right; ++x)
                {
                    ++histogramB[ptr->B];
                    ++histogramG[ptr->G];
                    ++histogramR[ptr->R];
                    ++ptr;
                }
            }
        }
        public static void RenderOneToOne(Surface dst, Surface source, Point offset)
        {
            unsafe
            {
                Rectangle srcRect = new Rectangle(offset, dst.Size);
                srcRect.Intersect(source.Bounds);

                for (int dstRow = 0; dstRow < srcRect.Height; ++dstRow)
                {
                    ColorBgra* dstRowPtr = dst.GetRowAddressUnchecked(dstRow);
                    ColorBgra* srcRowPtr = source.GetPointAddressUnchecked(offset.X, dstRow + offset.Y);

                    int dstCol = offset.X;
                    int dstColEnd = offset.X + srcRect.Width;
                    int checkerY = dstRow + offset.Y;

                    while (dstCol < dstColEnd)
                    {
                        int b = srcRowPtr->B;
                        int g = srcRowPtr->G;
                        int r = srcRowPtr->R;
                        int a = srcRowPtr->A;

                        // Blend it over the checkerboard background
                        int v = (((dstCol ^ checkerY) & 8) << 3) + 191;
                        a = a + (a >> 7);
                        int vmia = v * (256 - a);

                        r = ((r * a) + vmia) >> 8;
                        g = ((g * a) + vmia) >> 8;
                        b = ((b * a) + vmia) >> 8;

                        dstRowPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)255 << 24);
                        ++dstRowPtr;
                        ++srcRowPtr;
                        ++dstCol;
                    }
                }
            }
        }
        public static void RenderOneToOne(Surface dst, Surface source, Point offset)
        {
            unsafe
            {
                Rectangle srcRect = new Rectangle(offset, dst.Size);
                srcRect.Intersect(source.Bounds);

                for (int dstRow = 0; dstRow < srcRect.Height; ++dstRow)
                {
                    ColorBgra *dstRowPtr = dst.GetRowAddressUnchecked(dstRow);
                    ColorBgra *srcRowPtr = source.GetPointAddressUnchecked(offset.X, dstRow + offset.Y);

                    int dstCol    = offset.X;
                    int dstColEnd = offset.X + srcRect.Width;
                    int checkerY  = dstRow + offset.Y;

                    while (dstCol < dstColEnd)
                    {
                        int b = srcRowPtr->B;
                        int g = srcRowPtr->G;
                        int r = srcRowPtr->R;
                        int a = srcRowPtr->A;

                        // Blend it over the checkerboard background
                        int v = (((dstCol ^ checkerY) & 8) << 3) + 191;
                        a = a + (a >> 7);
                        int vmia = v * (256 - a);

                        r = ((r * a) + vmia) >> 8;
                        g = ((g * a) + vmia) >> 8;
                        b = ((b * a) + vmia) >> 8;

                        dstRowPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)255 << 24);
                        ++dstRowPtr;
                        ++srcRowPtr;
                        ++dstCol;
                    }
                }
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Clears a portion of a surface to transparent.
        /// </summary>
        /// <param name="surface">The surface to partially clear</param>
        /// <param name="roi">The rectangle to clear</param>
        private unsafe void ClearBackground(Surface surface, Rectangle roi)
        {
            roi.Intersect(surface.Bounds);

            for (int y = roi.Top; y < roi.Bottom; y++)
            {
                ColorBgra *ptr = surface.GetPointAddressUnchecked(roi.Left, y);
                Memory.SetToZero(ptr, (ulong)roi.Width * ColorBgra.SizeOf);
            }
        }
Ejemplo n.º 10
0
        public unsafe void SuperSampleFitSurface(Surface source)
        {
            Rectangle dstRoi2 = Rectangle.Intersect(source.Bounds, this.Bounds);

            for (int dstY = dstRoi2.Top; dstY < dstRoi2.Bottom; ++dstY)
            {
                double srcTop       = (double)(dstY * source.height) / (double)height;
                double srcTopFloor  = Math.Floor(srcTop);
                double srcTopWeight = 1 - (srcTop - srcTopFloor);
                int    srcTopInt    = (int)srcTopFloor;

                double srcBottom       = (double)((dstY + 1) * source.height) / (double)height;
                double srcBottomFloor  = Math.Floor(srcBottom - 0.00001);
                double srcBottomWeight = srcBottom - srcBottomFloor;
                int    srcBottomInt    = (int)srcBottomFloor;

                ColorBgra *dstPtr = this.GetPointAddressUnchecked(dstRoi2.Left, dstY);

                for (int dstX = dstRoi2.Left; dstX < dstRoi2.Right; ++dstX)
                {
                    double srcLeft       = (double)(dstX * source.width) / (double)width;
                    double srcLeftFloor  = Math.Floor(srcLeft);
                    double srcLeftWeight = 1 - (srcLeft - srcLeftFloor);
                    int    srcLeftInt    = (int)srcLeftFloor;

                    double srcRight       = (double)((dstX + 1) * source.width) / (double)width;
                    double srcRightFloor  = Math.Floor(srcRight - 0.00001);
                    double srcRightWeight = srcRight - srcRightFloor;
                    int    srcRightInt    = (int)srcRightFloor;

                    double blueSum  = 0;
                    double greenSum = 0;
                    double redSum   = 0;
                    double alphaSum = 0;

                    // left fractional edge
                    ColorBgra *srcLeftPtr = source.GetPointAddressUnchecked(srcLeftInt, srcTopInt + 1);

                    for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY)
                    {
                        double a = srcLeftPtr->A;
                        blueSum   += srcLeftPtr->B * srcLeftWeight * a;
                        greenSum  += srcLeftPtr->G * srcLeftWeight * a;
                        redSum    += srcLeftPtr->R * srcLeftWeight * a;
                        alphaSum  += srcLeftPtr->A * srcLeftWeight;
                        srcLeftPtr = (ColorBgra *)((byte *)srcLeftPtr + source.stride);
                    }

                    // right fractional edge
                    ColorBgra *srcRightPtr = source.GetPointAddressUnchecked(srcRightInt, srcTopInt + 1);
                    for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY)
                    {
                        double a = srcRightPtr->A;
                        blueSum    += srcRightPtr->B * srcRightWeight * a;
                        greenSum   += srcRightPtr->G * srcRightWeight * a;
                        redSum     += srcRightPtr->R * srcRightWeight * a;
                        alphaSum   += srcRightPtr->A * srcRightWeight;
                        srcRightPtr = (ColorBgra *)((byte *)srcRightPtr + source.stride);
                    }

                    // top fractional edge
                    ColorBgra *srcTopPtr = source.GetPointAddressUnchecked(srcLeftInt + 1, srcTopInt);
                    for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX)
                    {
                        double a = srcTopPtr->A;
                        blueSum  += srcTopPtr->B * srcTopWeight * a;
                        greenSum += srcTopPtr->G * srcTopWeight * a;
                        redSum   += srcTopPtr->R * srcTopWeight * a;
                        alphaSum += srcTopPtr->A * srcTopWeight;
                        ++srcTopPtr;
                    }

                    // bottom fractional edge
                    ColorBgra *srcBottomPtr = source.GetPointAddressUnchecked(srcLeftInt + 1, srcBottomInt);
                    for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX)
                    {
                        double a = srcBottomPtr->A;
                        blueSum  += srcBottomPtr->B * srcBottomWeight * a;
                        greenSum += srcBottomPtr->G * srcBottomWeight * a;
                        redSum   += srcBottomPtr->R * srcBottomWeight * a;
                        alphaSum += srcBottomPtr->A * srcBottomWeight;
                        ++srcBottomPtr;
                    }

                    // center area
                    for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY)
                    {
                        ColorBgra *srcPtr = source.GetPointAddressUnchecked(srcLeftInt + 1, srcY);

                        for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX)
                        {
                            double a = srcPtr->A;
                            blueSum  += (double)srcPtr->B * a;
                            greenSum += (double)srcPtr->G * a;
                            redSum   += (double)srcPtr->R * a;
                            alphaSum += (double)srcPtr->A;
                            ++srcPtr;
                        }
                    }

                    // four corner pixels
                    ColorBgra srcTL  = source.GetPoint(srcLeftInt, srcTopInt);
                    double    srcTLA = srcTL.A;
                    blueSum  += srcTL.B * (srcTopWeight * srcLeftWeight) * srcTLA;
                    greenSum += srcTL.G * (srcTopWeight * srcLeftWeight) * srcTLA;
                    redSum   += srcTL.R * (srcTopWeight * srcLeftWeight) * srcTLA;
                    alphaSum += srcTL.A * (srcTopWeight * srcLeftWeight);

                    ColorBgra srcTR  = source.GetPoint(srcRightInt, srcTopInt);
                    double    srcTRA = srcTR.A;
                    blueSum  += srcTR.B * (srcTopWeight * srcRightWeight) * srcTRA;
                    greenSum += srcTR.G * (srcTopWeight * srcRightWeight) * srcTRA;
                    redSum   += srcTR.R * (srcTopWeight * srcRightWeight) * srcTRA;
                    alphaSum += srcTR.A * (srcTopWeight * srcRightWeight);

                    ColorBgra srcBL  = source.GetPoint(srcLeftInt, srcBottomInt);
                    double    srcBLA = srcBL.A;
                    blueSum  += srcBL.B * (srcBottomWeight * srcLeftWeight) * srcBLA;
                    greenSum += srcBL.G * (srcBottomWeight * srcLeftWeight) * srcBLA;
                    redSum   += srcBL.R * (srcBottomWeight * srcLeftWeight) * srcBLA;
                    alphaSum += srcBL.A * (srcBottomWeight * srcLeftWeight);

                    ColorBgra srcBR  = source.GetPoint(srcRightInt, srcBottomInt);
                    double    srcBRA = srcBR.A;
                    blueSum  += srcBR.B * (srcBottomWeight * srcRightWeight) * srcBRA;
                    greenSum += srcBR.G * (srcBottomWeight * srcRightWeight) * srcBRA;
                    redSum   += srcBR.R * (srcBottomWeight * srcRightWeight) * srcBRA;
                    alphaSum += srcBR.A * (srcBottomWeight * srcRightWeight);

                    double area = (srcRight - srcLeft) * (srcBottom - srcTop);

                    double alpha = alphaSum / area;
                    double blue;
                    double green;
                    double red;

                    if (alpha == 0)
                    {
                        blue  = 0;
                        green = 0;
                        red   = 0;
                    }
                    else
                    {
                        blue  = blueSum / alphaSum;
                        green = greenSum / alphaSum;
                        red   = redSum / alphaSum;
                    }

                    // add 0.5 so that rounding goes in the direction we want it to
                    blue  += 0.5;
                    green += 0.5;
                    red   += 0.5;
                    alpha += 0.5;

                    dstPtr->Bgra = (uint)blue + ((uint)green << 8) + ((uint)red << 16) + ((uint)alpha << 24);
                    ++dstPtr;
                }
            }
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Implements bicubic filtering with bounds checking at every pixel.
        /// </summary>
        private unsafe void BicubicFitSurfaceChecked(Surface source, Rectangle dstRoi)
        {
            Rectangle roi   = Rectangle.Intersect(dstRoi, this.Bounds);
            Rectangle roiIn = Rectangle.Intersect(dstRoi, new Rectangle(1, 1, width - 1, height - 1));

            IntPtr  rColCacheIP = Memory.Allocate(4 * (ulong)roi.Width * (ulong)sizeof(double));
            double *rColCache   = (double *)rColCacheIP.ToPointer();

            // Precompute and then cache the value of R() for each column
            for (int dstX = roi.Left; dstX < roi.Right; ++dstX)
            {
                double srcColumn      = (double)(dstX * (source.width - 1)) / (double)(width - 1);
                double srcColumnFloor = Math.Floor(srcColumn);
                double srcColumnFrac  = srcColumn - srcColumnFloor;
                for (int m = -1; m <= 2; ++m)
                {
                    int    index = (m + 1) + ((dstX - roi.Left) * 4);
                    double x     = m - srcColumnFrac;
                    rColCache[index] = R(x);
                }
            }

            // Set this up so we can cache the R()'s for every row
            double *rRowCache = stackalloc double[4];

            for (int dstY = roi.Top; dstY < roi.Bottom; ++dstY)
            {
                double     srcRow      = (double)(dstY * (source.height - 1)) / (double)(height - 1);
                double     srcRowFloor = (double)Math.Floor(srcRow);
                double     srcRowFrac  = srcRow - srcRowFloor;
                int        srcRowInt   = (int)srcRow;
                ColorBgra *dstPtr      = this.GetPointAddressUnchecked(roi.Left, dstY);

                // Compute the R() values for this row
                for (int n = -1; n <= 2; ++n)
                {
                    double x = srcRowFrac - n;
                    rRowCache[n + 1] = R(x);
                }

                // See Perf Note below
                //int nFirst = Math.Max(-srcRowInt, -1);
                //int nLast = Math.Min(source.height - srcRowInt - 1, 2);

                for (int dstX = roi.Left; dstX < roi.Right; dstX++)
                {
                    double srcColumn      = (double)(dstX * (source.width - 1)) / (double)(width - 1);
                    double srcColumnFloor = Math.Floor(srcColumn);
                    double srcColumnFrac  = srcColumn - srcColumnFloor;
                    int    srcColumnInt   = (int)srcColumn;

                    double blueSum     = 0;
                    double greenSum    = 0;
                    double redSum      = 0;
                    double alphaSum    = 0;
                    double totalWeight = 0;

                    // See Perf Note below
                    //int mFirst = Math.Max(-srcColumnInt, -1);
                    //int mLast = Math.Min(source.width - srcColumnInt - 1, 2);

                    ColorBgra *srcPtr = source.GetPointAddressUnchecked(srcColumnInt - 1, srcRowInt - 1);

                    for (int n = -1; n <= 2; ++n)
                    {
                        int srcY = srcRowInt + n;

                        for (int m = -1; m <= 2; ++m)
                        {
                            // Perf Note: It actually benchmarks faster on my system to do
                            // a bounds check for every (m,n) than it is to limit the loop
                            // to nFirst-Last and mFirst-mLast.
                            // I'm leaving the code above, albeit commented out, so that
                            // benchmarking between these two can still be performed.
                            if (source.IsVisible(srcColumnInt + m, srcY))
                            {
                                double w0 = rColCache[(m + 1) + (4 * (dstX - roi.Left))];
                                double w1 = rRowCache[n + 1];
                                double w  = w0 * w1;

                                blueSum  += srcPtr->B * w * srcPtr->A;
                                greenSum += srcPtr->G * w * srcPtr->A;
                                redSum   += srcPtr->R * w * srcPtr->A;
                                alphaSum += srcPtr->A * w;

                                totalWeight += w;
                            }

                            ++srcPtr;
                        }

                        srcPtr = (ColorBgra *)((byte *)(srcPtr - 4) + source.stride);
                    }

                    double alpha = alphaSum / totalWeight;
                    double blue;
                    double green;
                    double red;

                    if (alpha == 0)
                    {
                        blue  = 0;
                        green = 0;
                        red   = 0;
                    }
                    else
                    {
                        blue  = blueSum / alphaSum;
                        green = greenSum / alphaSum;
                        red   = redSum / alphaSum;

                        // add 0.5 to ensure truncation to uint results in rounding
                        alpha += 0.5;
                        blue  += 0.5;
                        green += 0.5;
                        red   += 0.5;
                    }

                    dstPtr->Bgra = (uint)blue + ((uint)green << 8) + ((uint)red << 16) + ((uint)alpha << 24);
                    ++dstPtr;
                } // for (dstX...
            }     // for (dstY...

            Memory.Free(rColCacheIP);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Copies a region of the given surface to this surface.
        /// </summary>
        /// <param name="source">The surface to copy pixels from.</param>
        /// <param name="region">The region to clip copying to.</param>
        /// <remarks>
        /// The upper left corner of the source surface will be mapped to the upper left of this
        /// surface, and only those pixels that are defined by the region will be copied.
        /// The source surface does not need to have the same dimensions as this surface. Clipping
        /// will be handled automatically. No resizing will be done.
        /// </remarks>
        public void CopySurface(Surface source, Rectangle[] region, int startIndex, int length)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("Surface");
            }

            for (int i = startIndex; i < startIndex + length; ++i)
            {
                Rectangle rect = region[i];

                rect.Intersect(this.Bounds);
                rect.Intersect(source.Bounds);

                if (rect.Width == 0 || rect.Height == 0)
                {
                    continue;
                }

                unsafe
                {
                    for (int y = rect.Top; y < rect.Bottom; ++y)
                    {
                        ColorBgra* dst = this.GetPointAddressUnchecked(rect.Left, y);
                        ColorBgra* src = source.GetPointAddressUnchecked(rect.Left, y);
                        Memory.Copy(dst, src, (ulong)rect.Width * (ulong)ColorBgra.SizeOf);
                    }
                }
            }
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Copies a region of the given surface to this surface.
        /// </summary>
        /// <param name="source">The surface to copy pixels from.</param>
        /// <param name="region">The region to clip copying to.</param>
        /// <remarks>
        /// The upper left corner of the source surface will be mapped to the upper left of this
        /// surface, and only those pixels that are defined by the region will be copied.
        /// The source surface does not need to have the same dimensions as this surface. Clipping
        /// will be handled automatically. No resizing will be done.
        /// </remarks>
        public void CopySurface(Surface source, PdnRegion region)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("Surface");
            }

            Rectangle[] scans = region.GetRegionScansReadOnlyInt();
            for (int i = 0; i < scans.Length; ++i)
            {
                Rectangle rect = scans[i];

                rect.Intersect(this.Bounds);
                rect.Intersect(source.Bounds);

                if (rect.Width == 0 || rect.Height == 0)
                {
                    continue;
                }

                unsafe
                {
                    for (int y = rect.Top; y < rect.Bottom; ++y)
                    {
                        ColorBgra *dst = this.GetPointAddressUnchecked(rect.Left, y);
                        ColorBgra *src = source.GetPointAddressUnchecked(rect.Left, y);
                        Memory.Copy(dst, src, (ulong)rect.Width * (ulong)ColorBgra.SizeOf);
                    }
                }
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Implements bicubic filtering with bounds checking at every pixel.
        /// </summary>
        private void BicubicFitSurfaceChecked(Surface source, Rectangle dstRoi)
        {
            if (this.width < 2 || this.height < 2 || source.width < 2 || source.height < 2)
            {
                SuperSamplingFitSurface(source, dstRoi);
            }
            else
            {
                unsafe
                {
                    Rectangle roi = Rectangle.Intersect(dstRoi, this.Bounds);
                    Rectangle roiIn = Rectangle.Intersect(dstRoi, new Rectangle(1, 1, width - 1, height - 1));

                    IntPtr rColCacheIP = Memory.Allocate(4 * (ulong)roi.Width * (ulong)sizeof(double));
                    double* rColCache = (double*)rColCacheIP.ToPointer();

                    // Precompute and then cache the value of R() for each column
                    for (int dstX = roi.Left; dstX < roi.Right; ++dstX)
                    {
                        double srcColumn = (double)(dstX * (source.width - 1)) / (double)(width - 1);
                        double srcColumnFloor = Math.Floor(srcColumn);
                        double srcColumnFrac = srcColumn - srcColumnFloor;
                        int srcColumnInt = (int)srcColumn;

                        for (int m = -1; m <= 2; ++m)
                        {
                            int index = (m + 1) + ((dstX - roi.Left) * 4);
                            double x = m - srcColumnFrac;
                            rColCache[index] = R(x);
                        }
                    }

                    // Set this up so we can cache the R()'s for every row
                    double* rRowCache = stackalloc double[4];

                    for (int dstY = roi.Top; dstY < roi.Bottom; ++dstY)
                    {
                        double srcRow = (double)(dstY * (source.height - 1)) / (double)(height - 1);
                        double srcRowFloor = (double)Math.Floor(srcRow);
                        double srcRowFrac = srcRow - srcRowFloor;
                        int srcRowInt = (int)srcRow;
                        ColorBgra *dstPtr = this.GetPointAddressUnchecked(roi.Left, dstY);

                        // Compute the R() values for this row
                        for (int n = -1; n <= 2; ++n)
                        {
                            double x = srcRowFrac - n;
                            rRowCache[n + 1] = R(x);
                        }

                        // See Perf Note below
                        //int nFirst = Math.Max(-srcRowInt, -1);
                        //int nLast = Math.Min(source.height - srcRowInt - 1, 2);

                        for (int dstX = roi.Left; dstX < roi.Right; dstX++)
                        {
                            double srcColumn = (double)(dstX * (source.width - 1)) / (double)(width - 1);
                            double srcColumnFloor = Math.Floor(srcColumn);
                            double srcColumnFrac = srcColumn - srcColumnFloor;
                            int srcColumnInt = (int)srcColumn;

                            double blueSum = 0;
                            double greenSum = 0;
                            double redSum = 0;
                            double alphaSum = 0;
                            double totalWeight = 0;

                            // See Perf Note below
                            //int mFirst = Math.Max(-srcColumnInt, -1);
                            //int mLast = Math.Min(source.width - srcColumnInt - 1, 2);

                            ColorBgra *srcPtr = source.GetPointAddressUnchecked(srcColumnInt - 1, srcRowInt - 1);

                            for (int n = -1; n <= 2; ++n)
                            {
                                int srcY = srcRowInt + n;

                                for (int m = -1; m <= 2; ++m)
                                {
                                    // Perf Note: It actually benchmarks faster on my system to do
                                    // a bounds check for every (m,n) than it is to limit the loop
                                    // to nFirst-Last and mFirst-mLast.
                                    // I'm leaving the code above, albeit commented out, so that
                                    // benchmarking between these two can still be performed.
                                    if (source.IsVisible(srcColumnInt + m, srcY))
                                    {
                                        double w0 = rColCache[(m + 1) + (4 * (dstX - roi.Left))];
                                        double w1 = rRowCache[n + 1];
                                        double w = w0 * w1;

                                        blueSum += srcPtr->B * w * srcPtr->A;
                                        greenSum += srcPtr->G * w * srcPtr->A;
                                        redSum += srcPtr->R * w * srcPtr->A;
                                        alphaSum += srcPtr->A * w;

                                        totalWeight += w;
                                    }

                                    ++srcPtr;
                                }

                                srcPtr = (ColorBgra *)((byte *)(srcPtr - 4) + source.stride);
                            }

                            double alpha = alphaSum / totalWeight;
                            double blue;
                            double green;
                            double red;

                            if (alpha == 0)
                            {
                                blue = 0;
                                green = 0;
                                red = 0;
                            }
                            else
                            {
                                blue = blueSum / alphaSum;
                                green = greenSum / alphaSum;
                                red = redSum / alphaSum;

                                // add 0.5 to ensure truncation to uint results in rounding
                                alpha += 0.5;
                                blue += 0.5;
                                green += 0.5;
                                red += 0.5;
                            }

                            dstPtr->Bgra = (uint)blue + ((uint)green << 8) + ((uint)red << 16) + ((uint)alpha << 24);
                            ++dstPtr;
                        } // for (dstX...
                    } // for (dstY...

                    Memory.Free(rColCacheIP);
                } // unsafe
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Fits the source surface to this surface using super sampling. If the source surface is less wide
        /// or less tall than this surface (i.e. magnification), bicubic resampling is used instead. If either
        /// the source or destination has a dimension that is only 1 pixel, nearest neighbor is used.
        /// </summary>
        /// <param name="source">The surface to read pixels from.</param>
        /// <param name="dstRoi">The rectangle to clip rendering to.</param>
        /// <remarks>This method was implemented with correctness, not performance, in mind.</remarks>
        public void SuperSamplingFitSurface(Surface source, Rectangle dstRoi)
        {
            if (source.Width == Width && source.Height == Height)
            {
                CopySurface(source);
            }
            else if (source.Width <= Width || source.Height <= Height)
            {
                if (source.width < 2 || source.height < 2 || this.width < 2 || this.height < 2)
                {
                    this.NearestNeighborFitSurface(source, dstRoi);
                }
                else
                {
                    this.BicubicFitSurface(source, dstRoi);
                }
            }
            else unsafe
            {
                Rectangle dstRoi2 = Rectangle.Intersect(dstRoi, this.Bounds);

                for (int dstY = dstRoi2.Top; dstY < dstRoi2.Bottom; ++dstY)
                {
                    double srcTop = (double)(dstY * source.height) / (double)height;
                    double srcTopFloor = Math.Floor(srcTop);
                    double srcTopWeight = 1 - (srcTop - srcTopFloor);
                    int srcTopInt = (int)srcTopFloor;

                    double srcBottom = (double)((dstY + 1) * source.height) / (double)height;
                    double srcBottomFloor = Math.Floor(srcBottom - 0.00001);
                    double srcBottomWeight = srcBottom - srcBottomFloor;
                    int srcBottomInt = (int)srcBottomFloor;

                    ColorBgra *dstPtr = this.GetPointAddressUnchecked(dstRoi2.Left, dstY);

                    for (int dstX = dstRoi2.Left; dstX < dstRoi2.Right; ++dstX)
                    {
                        double srcLeft = (double)(dstX * source.width) / (double)width;
                        double srcLeftFloor = Math.Floor(srcLeft);
                        double srcLeftWeight = 1 - (srcLeft - srcLeftFloor);
                        int srcLeftInt = (int)srcLeftFloor;

                        double srcRight = (double)((dstX + 1) * source.width) / (double)width;
                        double srcRightFloor = Math.Floor(srcRight - 0.00001);
                        double srcRightWeight = srcRight - srcRightFloor;
                        int srcRightInt = (int)srcRightFloor;

                        double blueSum = 0;
                        double greenSum = 0;
                        double redSum = 0;
                        double alphaSum = 0;

                        // left fractional edge
                        ColorBgra *srcLeftPtr = source.GetPointAddressUnchecked(srcLeftInt, srcTopInt + 1);

                        for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY)
                        {
                            double a = srcLeftPtr->A;
                            blueSum += srcLeftPtr->B * srcLeftWeight * a;
                            greenSum += srcLeftPtr->G * srcLeftWeight * a;
                            redSum += srcLeftPtr->R * srcLeftWeight * a;
                            alphaSum += srcLeftPtr->A * srcLeftWeight;
                            srcLeftPtr = (ColorBgra*)((byte*)srcLeftPtr + source.stride);
                        }

                        // right fractional edge
                        ColorBgra *srcRightPtr = source.GetPointAddressUnchecked(srcRightInt, srcTopInt + 1);
                        for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY)
                        {
                            double a = srcRightPtr->A;
                            blueSum += srcRightPtr->B * srcRightWeight * a;
                            greenSum += srcRightPtr->G * srcRightWeight * a;
                            redSum += srcRightPtr->R * srcRightWeight * a;
                            alphaSum += srcRightPtr->A * srcRightWeight;
                            srcRightPtr = (ColorBgra*)((byte*)srcRightPtr + source.stride);
                        }

                        // top fractional edge
                        ColorBgra *srcTopPtr = source.GetPointAddressUnchecked(srcLeftInt + 1, srcTopInt);
                        for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX)
                        {
                            double a = srcTopPtr->A;
                            blueSum += srcTopPtr->B * srcTopWeight * a;
                            greenSum += srcTopPtr->G * srcTopWeight * a;
                            redSum += srcTopPtr->R * srcTopWeight * a;
                            alphaSum += srcTopPtr->A * srcTopWeight;
                            ++srcTopPtr;
                        }

                        // bottom fractional edge
                        ColorBgra *srcBottomPtr = source.GetPointAddressUnchecked(srcLeftInt + 1, srcBottomInt);
                        for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX)
                        {
                            double a = srcBottomPtr->A;
                            blueSum += srcBottomPtr->B * srcBottomWeight * a;
                            greenSum += srcBottomPtr->G * srcBottomWeight * a;
                            redSum += srcBottomPtr->R * srcBottomWeight * a;
                            alphaSum += srcBottomPtr->A * srcBottomWeight;
                            ++srcBottomPtr;
                        }

                        // center area
                        for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY)
                        {
                            ColorBgra *srcPtr = source.GetPointAddressUnchecked(srcLeftInt + 1, srcY);

                            for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX)
                            {
                                double a = srcPtr->A;
                                blueSum += (double)srcPtr->B * a;
                                greenSum += (double)srcPtr->G * a;
                                redSum += (double)srcPtr->R * a;
                                alphaSum += (double)srcPtr->A;
                                ++srcPtr;
                            }
                        }

                        // four corner pixels
                        ColorBgra srcTL = source.GetPoint(srcLeftInt, srcTopInt);
                        double srcTLA = srcTL.A;
                        blueSum += srcTL.B * (srcTopWeight * srcLeftWeight) * srcTLA;
                        greenSum += srcTL.G * (srcTopWeight * srcLeftWeight) * srcTLA;
                        redSum += srcTL.R * (srcTopWeight * srcLeftWeight) * srcTLA;
                        alphaSum += srcTL.A * (srcTopWeight * srcLeftWeight);

                        ColorBgra srcTR = source.GetPoint(srcRightInt, srcTopInt);
                        double srcTRA = srcTR.A;
                        blueSum += srcTR.B * (srcTopWeight * srcRightWeight) * srcTRA;
                        greenSum += srcTR.G * (srcTopWeight * srcRightWeight) * srcTRA;
                        redSum += srcTR.R * (srcTopWeight * srcRightWeight) * srcTRA;
                        alphaSum += srcTR.A * (srcTopWeight * srcRightWeight);

                        ColorBgra srcBL = source.GetPoint(srcLeftInt, srcBottomInt);
                        double srcBLA = srcBL.A;
                        blueSum += srcBL.B * (srcBottomWeight * srcLeftWeight) * srcBLA;
                        greenSum += srcBL.G * (srcBottomWeight * srcLeftWeight) * srcBLA;
                        redSum += srcBL.R * (srcBottomWeight * srcLeftWeight) * srcBLA;
                        alphaSum += srcBL.A * (srcBottomWeight * srcLeftWeight);

                        ColorBgra srcBR = source.GetPoint(srcRightInt, srcBottomInt);
                        double srcBRA = srcBR.A;
                        blueSum += srcBR.B * (srcBottomWeight * srcRightWeight) * srcBRA;
                        greenSum += srcBR.G * (srcBottomWeight * srcRightWeight) * srcBRA;
                        redSum += srcBR.R * (srcBottomWeight * srcRightWeight) * srcBRA;
                        alphaSum += srcBR.A * (srcBottomWeight * srcRightWeight);

                        double area = (srcRight - srcLeft) * (srcBottom - srcTop);

                        double alpha = alphaSum / area;
                        double blue;
                        double green;
                        double red;

                        if (alpha == 0)
                        {
                            blue = 0;
                            green = 0;
                            red = 0;
                        }
                        else
                        {
                            blue = blueSum / alphaSum;
                            green = greenSum / alphaSum;
                            red = redSum / alphaSum;
                        }

                        // add 0.5 so that rounding goes in the direction we want it to
                        blue += 0.5;
                        green += 0.5;
                        red += 0.5;
                        alpha += 0.5;

                        dstPtr->Bgra = (uint)blue + ((uint)green << 8) + ((uint)red << 16) + ((uint)alpha << 24);
                        ++dstPtr;
                    }
                }
            }
        }
Ejemplo n.º 16
0
        private unsafe void DrawText(Surface dst, Font textFont, string text, Point pt, Size measuredSize, bool antiAliasing, Surface brush8x8)
        {
            Point pt2 = pt;
            Size measuredSize2 = measuredSize;
            int offset = (int)textFont.Height;
            pt.X -= offset;
            measuredSize.Width += 2 * offset;
            Rectangle dstRect = new Rectangle(pt, measuredSize);
            Rectangle dstRectClipped = Rectangle.Intersect(dstRect, ScratchSurface.Bounds);

            if (dstRectClipped.Width == 0 || dstRectClipped.Height == 0)
            {
                return;
            }

            // We only use the first 8,8 of brush
            using (RenderArgs renderArgs = new RenderArgs(this.ScratchSurface))
            {
                renderArgs.Graphics.FillRectangle(Brushes.White, pt.X, pt.Y, measuredSize.Width, measuredSize.Height);

                if (measuredSize.Width > 0 && measuredSize.Height > 0)
                {
                    using (Surface s2 = renderArgs.Surface.CreateWindow(dstRectClipped))
                    {
                        using (RenderArgs renderArgs2 = new RenderArgs(s2))
                        {
                            SystemLayer.Fonts.DrawText(
                                renderArgs2.Graphics, 
                                this.font, 
                                text, 
                                new Point(dstRect.X - dstRectClipped.X + offset, dstRect.Y - dstRectClipped.Y),
                                AppEnvironment.AntiAliasing,
                                AppEnvironment.FontSmoothing);
                        }
                    }
                }

                // Mask out anything that isn't within the user's clip region (selected region)
                using (PdnRegion clip = Selection.CreateRegion())
                {
                    clip.Xor(renderArgs.Surface.Bounds); // invert
                    clip.Intersect(new Rectangle(pt, measuredSize));
                    renderArgs.Graphics.FillRegion(Brushes.White, clip.GetRegionReadOnly());
                }

                int skipX;

                if (pt.X < 0)
                {
                    skipX = -pt.X;
                }
                else
                {
                    skipX = 0;
                }

                int xEnd = Math.Min(dst.Width, pt.X + measuredSize.Width);

                bool blending = AppEnvironment.AlphaBlending;

                if (dst.IsColumnVisible(pt.X + skipX))
                {
                    for (int y = pt.Y; y < pt.Y + measuredSize.Height; ++y)
                    {
                        if (!dst.IsRowVisible(y))
                        {
                            continue;
                        }

                        ColorBgra *dstPtr = dst.GetPointAddressUnchecked(pt.X + skipX, y);
                        ColorBgra *srcPtr = ScratchSurface.GetPointAddress(pt.X + skipX, y);
                        ColorBgra *brushPtr = brush8x8.GetRowAddressUnchecked(y & 7);

                        for (int x = pt.X + skipX; x < xEnd; ++x)
                        {
                            ColorBgra srcPixel = *srcPtr;
                            ColorBgra dstPixel = *dstPtr;
                            ColorBgra brushPixel = brushPtr[x & 7];

                            int alpha = ((255 - srcPixel.R) * brushPixel.A) / 255; // we could use srcPixel.R, .G, or .B -- the choice here is arbitrary
                            brushPixel.A = (byte)alpha;

                            if (srcPtr->R == 255) // could use R, G, or B -- arbitrary choice
                            {
                                // do nothing -- leave dst alone
                            }
                            else if (alpha == 255 || !blending)
                            {
                                // copy it straight over
                                *dstPtr = brushPixel;
                            }
                            else
                            {
                                // do expensive blending
                                *dstPtr = UserBlendOps.NormalBlendOp.ApplyStatic(dstPixel, brushPixel);
                            }

                            ++dstPtr;
                            ++srcPtr;
                        }
                    }
                }
            }
        }