Пример #1
0
        /// <summary>
        /// Copies the contents of the given surface to the upper left corner of this surface.
        /// </summary>
        /// <param name="source">The surface to copy pixels from.</param>
        /// <remarks>
        /// 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)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("Surface");
            }

            if (this.stride == source.stride &&
                (this.width * ColorBgra.SizeOf) == this.stride &&
                this.width == source.width &&
                this.height == source.height)
            {
                unsafe
                {
                    Memory.Copy(this.scan0.VoidStar,
                                source.scan0.VoidStar,
                                ((ulong)(height - 1) * (ulong)stride) + ((ulong)width * (ulong)ColorBgra.SizeOf));
                }
            }
            else
            {
                int copyWidth  = Math.Min(width, source.width);
                int copyHeight = Math.Min(height, source.height);

                unsafe
                {
                    for (int y = 0; y < copyHeight; ++y)
                    {
                        Memory.Copy(GetRowAddressUnchecked(y), source.GetRowAddressUnchecked(y), (ulong)copyWidth * (ulong)ColorBgra.SizeOf);
                    }
                }
            }
        }
Пример #2
0
        protected override void OnSave(Document input, Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler progressCallback)
        {
            GifSaveConfigToken gsct = (GifSaveConfigToken)token;

            // Flatten and pre-process the image
            scratchSurface.Clear(ColorBgra.FromBgra(255, 255, 255, 0));

            using (RenderArgs ra = new RenderArgs(scratchSurface))
            {
                input.Render(ra, true);
            }

            for (int y = 0; y < scratchSurface.Height; ++y)
            {
                unsafe
                {
                    ColorBgra* ptr = scratchSurface.GetRowAddressUnchecked(y);

                    for (int x = 0; x < scratchSurface.Width; ++x)
                    {
                        if (ptr->A < gsct.Threshold)
                        {
                            ptr->Bgra = 0;
                        }
                        else
                        {
                            if (gsct.PreMultiplyAlpha)
                            {
                                int r = ((ptr->R * ptr->A) + (255 * (255 - ptr->A))) / 255;
                                int g = ((ptr->G * ptr->A) + (255 * (255 - ptr->A))) / 255;
                                int b = ((ptr->B * ptr->A) + (255 * (255 - ptr->A))) / 255;
                                int a = 255;

                                *ptr = ColorBgra.FromBgra((byte)b, (byte)g, (byte)r, (byte)a);
                            }
                            else
                            {
                                ptr->Bgra |= 0xff000000;
                            }
                        }

                        ++ptr;
                    }
                }
            }

            using (Bitmap quantized = Quantize(scratchSurface, gsct.DitherLevel, 255, progressCallback))
            {
                quantized.Save(output, ImageFormat.Gif);
            }
        }
Пример #3
0
        protected override void OnSave(Document input, Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler progressCallback)
        {
            GifSaveConfigToken gsct = (GifSaveConfigToken)token;

            // Flatten and pre-process the image
            scratchSurface.Clear(ColorBgra.FromBgra(255, 255, 255, 0));

            using (RenderArgs ra = new RenderArgs(scratchSurface))
            {
                input.Render(ra, true);
            }

            for (int y = 0; y < scratchSurface.Height; ++y)
            {
                unsafe
                {
                    ColorBgra *ptr = scratchSurface.GetRowAddressUnchecked(y);

                    for (int x = 0; x < scratchSurface.Width; ++x)
                    {
                        if (ptr->A < gsct.Threshold)
                        {
                            ptr->Bgra = 0;
                        }
                        else
                        {
                            if (gsct.PreMultiplyAlpha)
                            {
                                int r = ((ptr->R * ptr->A) + (255 * (255 - ptr->A))) / 255;
                                int g = ((ptr->G * ptr->A) + (255 * (255 - ptr->A))) / 255;
                                int b = ((ptr->B * ptr->A) + (255 * (255 - ptr->A))) / 255;
                                int a = 255;

                                *ptr = ColorBgra.FromBgra((byte)b, (byte)g, (byte)r, (byte)a);
                            }
                            else
                            {
                                ptr->Bgra |= 0xff000000;
                            }
                        }

                        ++ptr;
                    }
                }
            }

            using (Bitmap quantized = Quantize(scratchSurface, gsct.DitherLevel, 255, progressCallback))
            {
                quantized.Save(output, ImageFormat.Gif);
            }
        }
Пример #4
0
        public void Apply(Surface dst, Surface lhs, Surface rhs)
        {
            if (dst.Size != lhs.Size)
            {
                throw new ArgumentException("dst.Size != lhs.Size");
            }

            if (lhs.Size != rhs.Size)
            {
                throw new ArgumentException("lhs.Size != rhs.Size");
            }

            unsafe
            {
                for (int y = 0; y < dst.Height; ++y)
                {
                    ColorBgra *dstPtr = dst.GetRowAddressUnchecked(y);
                    ColorBgra *lhsPtr = lhs.GetRowAddressUnchecked(y);
                    ColorBgra *rhsPtr = lhs.GetRowAddressUnchecked(y);

                    Apply(dstPtr, lhsPtr, rhsPtr, dst.Width);
                }
            }
        }
Пример #5
0
        public void Apply(Surface dst, Surface src)
        {
            if (dst.Size != src.Size)
            {
                throw new ArgumentException("dst.Size != src.Size");
            }

            unsafe {
                for (int y = 0; y < dst.Height; ++y)
                {
                    ColorBgra *dstPtr = dst.GetRowAddressUnchecked(y);
                    ColorBgra *srcPtr = src.GetRowAddressUnchecked(y);
                    Apply(dstPtr, srcPtr, dst.Width);
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Creates a new Surface and copies the pixels from a Bitmap to it.
        /// </summary>
        /// <param name="bitmap">The Bitmap to duplicate.</param>
        /// <returns>A new Surface that is the same size as the given Bitmap and that has the same pixel values.</returns>
        public static Surface CopyFromBitmap(Bitmap bitmap)
        {
            Surface    surface = new Surface(bitmap.Width, bitmap.Height);
            BitmapData bd      = bitmap.LockBits(surface.Bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

            unsafe
            {
                for (int y = 0; y < bd.Height; ++y)
                {
                    Memory.Copy((void *)surface.GetRowAddressUnchecked(y),
                                (byte *)bd.Scan0.ToPointer() + (y * bd.Stride), (ulong)bd.Width * ColorBgra.SizeOf);
                }
            }

            bitmap.UnlockBits(bd);
            return(surface);
        }
        private void RenderZoomInNearestNeighbor(Surface dst, Point offset)
        {
            unsafe
            {
                int[] d2SLookupY = OwnerList.Dst2SrcLookupY;
                int[] d2SLookupX = OwnerList.Dst2SrcLookupX;

                for (int dstRow = 0; dstRow < dst.Height; ++dstRow)
                {
                    int        nnY    = dstRow + offset.Y;
                    int        srcY   = d2SLookupY[nnY];
                    ColorBgra *dstPtr = dst.GetRowAddressUnchecked(dstRow);
                    ColorBgra *srcRow = this.source.GetRowAddressUnchecked(srcY);

                    for (int dstCol = 0; dstCol < dst.Width; ++dstCol)
                    {
                        int nnX  = dstCol + offset.X;
                        int srcX = d2SLookupX[nnX];

                        ColorBgra src = *(srcRow + srcX);
                        int       b   = src.B;
                        int       g   = src.G;
                        int       r   = src.R;
                        int       a   = src.A;

                        // Blend it over the checkerboard background
                        int v = (((dstCol + offset.X) ^ (dstRow + offset.Y)) & 8) * 8 + 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;

                        dstPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)255 << 24);

                        ++dstPtr;
                    }
                }
            }
        }
        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;
                    }
                }
            }
        }
Пример #10
0
        /// <summary>
        /// Implements bicubic filtering with NO bounds checking at any pixel.
        /// </summary>
        private unsafe void BicubicFitSurfaceUnchecked(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 = 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);
                }

                rColCache = (double *)rColCacheIP.ToPointer();
                ColorBgra *srcRowPtr = source.GetRowAddressUnchecked(srcRowInt - 1);

                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;

                    ColorBgra *srcPtr = srcRowPtr + srcColumnInt - 1;
                    for (int n = 0; n <= 3; ++n)
                    {
                        double w0 = rColCache[0] * rRowCache[n];
                        double w1 = rColCache[1] * rRowCache[n];
                        double w2 = rColCache[2] * rRowCache[n];
                        double w3 = rColCache[3] * rRowCache[n];

                        double a0 = srcPtr[0].A;
                        double a1 = srcPtr[1].A;
                        double a2 = srcPtr[2].A;
                        double a3 = srcPtr[3].A;

                        alphaSum    += (a0 * w0) + (a1 * w1) + (a2 * w2) + (a3 * w3);
                        totalWeight += w0 + w1 + w2 + w3;

                        blueSum  += (a0 * srcPtr[0].B * w0) + (a1 * srcPtr[1].B * w1) + (a2 * srcPtr[2].B * w2) + (a3 * srcPtr[3].B * w3);
                        greenSum += (a0 * srcPtr[0].G * w0) + (a1 * srcPtr[1].G * w1) + (a2 * srcPtr[2].G * w2) + (a3 * srcPtr[3].G * w3);
                        redSum   += (a0 * srcPtr[0].R * w0) + (a1 * srcPtr[1].R * w1) + (a2 * srcPtr[2].R * w2) + (a3 * srcPtr[3].R * w3);

                        srcPtr = (ColorBgra *)((byte *)srcPtr + 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;
                    rColCache += 4;
                } // for (dstX...
            }     // for (dstY...

            Memory.Free(rColCacheIP);
        }
Пример #11
0
        private unsafe void DrawACircle(PointF pt, Surface srfSrc, Surface srfDst, Point difference, Rectangle rect) 
        {
            float bw = AppEnvironment.PenInfo.Width / 2;
            float envAlpha = AppEnvironment.PrimaryColor.A / 255.0f;

            rect.Intersect(new Rectangle(difference, srfSrc.Size));
            rect.Intersect(srfDst.Bounds);

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

            // envAlpha = envAlpha^4
            envAlpha *= envAlpha;
            envAlpha *= envAlpha;

            for (int y = rect.Top; y < rect.Bottom; y++) 
            {
                ColorBgra *srcRow = srfSrc.GetRowAddressUnchecked(y - difference.Y);
                ColorBgra *dstRow = srfDst.GetRowAddressUnchecked(y);

                for (int x = rect.Left; x < rect.Right; x++) 
                {
                    ColorBgra *srcPtr = unchecked(srcRow + x - difference.X);
                    ColorBgra *dstPtr = unchecked(dstRow + x);
                    float distFromRing = 0.5f + bw - Utility.Distance(pt, new PointF(x, y));

                    if (distFromRing > 0)
                    {
                        float alpha = antialiasing ? Utility.Clamp(distFromRing * envAlpha, 0, 1) : 1;
                        alpha *= srcPtr->A / 255.0f;
                        dstPtr->A = (byte)(255 - (255 - dstPtr->A) * (1 - alpha));

                        if (0 == (alpha + (1 - alpha) * dstPtr->A / 255))
                        {
                            dstPtr->Bgra = 0;
                        }
                        else
                        {
                            dstPtr->R = (byte)((srcPtr->R * alpha + dstPtr->R * (1 - alpha) * dstPtr->A / 255) / (alpha + (1 - alpha) * dstPtr->A / 255));
                            dstPtr->G = (byte)((srcPtr->G * alpha + dstPtr->G * (1 - alpha) * dstPtr->A / 255) / (alpha + (1 - alpha) * dstPtr->A / 255));
                            dstPtr->B = (byte)((srcPtr->B * alpha + dstPtr->B * (1 - alpha) * dstPtr->A / 255) / (alpha + (1 - alpha) * dstPtr->A / 255));
                        }
                    }
                }
            }

            rect.Inflate(1, 1);
            Document.Invalidate(rect);
        }
Пример #12
0
        public void Apply(Surface dst, Surface src)
        {
            if (dst.Size != src.Size)
            {
                throw new ArgumentException("dst.Size != src.Size");
            }

            unsafe
            {
                for (int y = 0; y < dst.Height; ++y)
                {
                    ColorBgra *dstPtr = dst.GetRowAddressUnchecked(y);
                    ColorBgra *srcPtr = src.GetRowAddressUnchecked(y);
                    Apply(dstPtr, srcPtr, dst.Width);
                }
            }
        }
Пример #13
0
        public void Apply(Surface dst, Surface lhs, Surface rhs)
        {
            if (dst.Size != lhs.Size)
            {
                throw new ArgumentException("dst.Size != lhs.Size");
            }

            if (lhs.Size != rhs.Size)
            {
                throw new ArgumentException("lhs.Size != rhs.Size");
            }

            unsafe
            {
                for (int y = 0; y < dst.Height; ++y)
                {
                    ColorBgra *dstPtr = dst.GetRowAddressUnchecked(y);
                    ColorBgra *lhsPtr = lhs.GetRowAddressUnchecked(y);
                    ColorBgra *rhsPtr = lhs.GetRowAddressUnchecked(y);

                    Apply(dstPtr, lhsPtr, rhsPtr, dst.Width);
                }
            }
        }
        private void RenderZoomInNearestNeighbor(Surface dst, Point offset)
        {
            unsafe
            {
                int[] d2SLookupY = OwnerList.Dst2SrcLookupY;
                int[] d2SLookupX = OwnerList.Dst2SrcLookupX;

                for (int dstRow = 0; dstRow < dst.Height; ++dstRow)
                {
                    int nnY = dstRow + offset.Y;
                    int srcY = d2SLookupY[nnY];
                    ColorBgra *dstPtr = dst.GetRowAddressUnchecked(dstRow);
                    ColorBgra *srcRow = this.source.GetRowAddressUnchecked(srcY);

                    for (int dstCol = 0; dstCol < dst.Width; ++dstCol)
                    {
                        int nnX = dstCol + offset.X;
                        int srcX = d2SLookupX[nnX];

                        ColorBgra src = *(srcRow + srcX);
                        int b = src.B;
                        int g = src.G;
                        int r = src.R;
                        int a = src.A;

                        // Blend it over the checkerboard background
                        int v = (((dstCol + offset.X) ^ (dstRow + offset.Y)) & 8) * 8 + 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;

                        dstPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)255 << 24);

                        ++dstPtr;
                    }
                }
            }
        }
        public static void RenderZoomOutRotatedGridMultisampling(Surface dst, Surface source, Point offset, Size destinationSize)
        {
            unsafe
            {
                const int fpShift = 12;
                const int fpFactor = (1 << fpShift);

                Size sourceSize = source.Size;
                long fDstLeftLong = ((long)offset.X * fpFactor * (long)sourceSize.Width) / (long)destinationSize.Width;
                long fDstTopLong = ((long)offset.Y * fpFactor * (long)sourceSize.Height) / (long)destinationSize.Height;
                long fDstRightLong = ((long)(offset.X + dst.Width) * fpFactor * (long)sourceSize.Width) / (long)destinationSize.Width;
                long fDstBottomLong = ((long)(offset.Y + dst.Height) * fpFactor * (long)sourceSize.Height) / (long)destinationSize.Height;
                int fDstLeft = (int)fDstLeftLong;
                int fDstTop = (int)fDstTopLong;
                int fDstRight = (int)fDstRightLong;
                int fDstBottom = (int)fDstBottomLong;
                int dx = (fDstRight - fDstLeft) / dst.Width;
                int dy = (fDstBottom - fDstTop) / dst.Height;

                for (int dstRow = 0, fDstY = fDstTop;
                    dstRow < dst.Height && fDstY < fDstBottom;
                    ++dstRow, fDstY += dy)
                {
                    int srcY1 = fDstY >> fpShift;                            // y
                    int srcY2 = (fDstY + (dy >> 2)) >> fpShift;              // y + 0.25
                    int srcY3 = (fDstY + (dy >> 1)) >> fpShift;              // y + 0.50
                    int srcY4 = (fDstY + (dy >> 1) + (dy >> 2)) >> fpShift;  // y + 0.75

            #if DEBUG
                    Debug.Assert(source.IsRowVisible(srcY1));
                    Debug.Assert(source.IsRowVisible(srcY2));
                    Debug.Assert(source.IsRowVisible(srcY3));
                    Debug.Assert(source.IsRowVisible(srcY4));
                    Debug.Assert(dst.IsRowVisible(dstRow));
            #endif

                    ColorBgra* src1 = source.GetRowAddressUnchecked(srcY1);
                    ColorBgra* src2 = source.GetRowAddressUnchecked(srcY2);
                    ColorBgra* src3 = source.GetRowAddressUnchecked(srcY3);
                    ColorBgra* src4 = source.GetRowAddressUnchecked(srcY4);
                    ColorBgra* dstPtr = dst.GetRowAddressUnchecked(dstRow);
                    int checkerY = dstRow + offset.Y;
                    int checkerX = offset.X;
                    int maxCheckerX = checkerX + dst.Width;

                    for (int fDstX = fDstLeft;
                         checkerX < maxCheckerX && fDstX < fDstRight;
                         ++checkerX, fDstX += dx)
                    {
                        int srcX1 = (fDstX + (dx >> 2)) >> fpShift;             // x + 0.25
                        int srcX2 = (fDstX + (dx >> 1) + (dx >> 2)) >> fpShift; // x + 0.75
                        int srcX3 = fDstX >> fpShift;                           // x
                        int srcX4 = (fDstX + (dx >> 1)) >> fpShift;             // x + 0.50

            #if DEBUG
                        Debug.Assert(source.IsColumnVisible(srcX1));
                        Debug.Assert(source.IsColumnVisible(srcX2));
                        Debug.Assert(source.IsColumnVisible(srcX3));
                        Debug.Assert(source.IsColumnVisible(srcX4));
            #endif

                        ColorBgra* p1 = src1 + srcX1;
                        ColorBgra* p2 = src2 + srcX2;
                        ColorBgra* p3 = src3 + srcX3;
                        ColorBgra* p4 = src4 + srcX4;

                        int r = (2 + p1->R + p2->R + p3->R + p4->R) >> 2;
                        int g = (2 + p1->G + p2->G + p3->G + p4->G) >> 2;
                        int b = (2 + p1->B + p2->B + p3->B + p4->B) >> 2;
                        int a = (2 + p1->A + p2->A + p3->A + p4->A) >> 2;

                        // Blend it over the checkerboard background
                        int v = ((checkerX ^ checkerY) & 8) * 8 + 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;

                        dstPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + 0xff000000;
                        ++dstPtr;
                    }
                }
            }
        }
        public static void RenderZoomOutRotatedGridMultisampling(Surface dst, Surface source, Point offset, Size destinationSize)
        {
            unsafe
            {
                const int fpShift  = 12;
                const int fpFactor = (1 << fpShift);

                Size sourceSize     = source.Size;
                long fDstLeftLong   = ((long)offset.X * fpFactor * (long)sourceSize.Width) / (long)destinationSize.Width;
                long fDstTopLong    = ((long)offset.Y * fpFactor * (long)sourceSize.Height) / (long)destinationSize.Height;
                long fDstRightLong  = ((long)(offset.X + dst.Width) * fpFactor * (long)sourceSize.Width) / (long)destinationSize.Width;
                long fDstBottomLong = ((long)(offset.Y + dst.Height) * fpFactor * (long)sourceSize.Height) / (long)destinationSize.Height;
                int  fDstLeft       = (int)fDstLeftLong;
                int  fDstTop        = (int)fDstTopLong;
                int  fDstRight      = (int)fDstRightLong;
                int  fDstBottom     = (int)fDstBottomLong;
                int  dx             = (fDstRight - fDstLeft) / dst.Width;
                int  dy             = (fDstBottom - fDstTop) / dst.Height;

                for (int dstRow = 0, fDstY = fDstTop;
                     dstRow < dst.Height && fDstY < fDstBottom;
                     ++dstRow, fDstY += dy)
                {
                    int srcY1 = fDstY >> fpShift;                            // y
                    int srcY2 = (fDstY + (dy >> 2)) >> fpShift;              // y + 0.25
                    int srcY3 = (fDstY + (dy >> 1)) >> fpShift;              // y + 0.50
                    int srcY4 = (fDstY + (dy >> 1) + (dy >> 2)) >> fpShift;  // y + 0.75

#if DEBUG
                    Debug.Assert(source.IsRowVisible(srcY1));
                    Debug.Assert(source.IsRowVisible(srcY2));
                    Debug.Assert(source.IsRowVisible(srcY3));
                    Debug.Assert(source.IsRowVisible(srcY4));
                    Debug.Assert(dst.IsRowVisible(dstRow));
#endif

                    ColorBgra *src1        = source.GetRowAddressUnchecked(srcY1);
                    ColorBgra *src2        = source.GetRowAddressUnchecked(srcY2);
                    ColorBgra *src3        = source.GetRowAddressUnchecked(srcY3);
                    ColorBgra *src4        = source.GetRowAddressUnchecked(srcY4);
                    ColorBgra *dstPtr      = dst.GetRowAddressUnchecked(dstRow);
                    int        checkerY    = dstRow + offset.Y;
                    int        checkerX    = offset.X;
                    int        maxCheckerX = checkerX + dst.Width;

                    for (int fDstX = fDstLeft;
                         checkerX < maxCheckerX && fDstX < fDstRight;
                         ++checkerX, fDstX += dx)
                    {
                        int srcX1 = (fDstX + (dx >> 2)) >> fpShift;             // x + 0.25
                        int srcX2 = (fDstX + (dx >> 1) + (dx >> 2)) >> fpShift; // x + 0.75
                        int srcX3 = fDstX >> fpShift;                           // x
                        int srcX4 = (fDstX + (dx >> 1)) >> fpShift;             // x + 0.50

#if DEBUG
                        Debug.Assert(source.IsColumnVisible(srcX1));
                        Debug.Assert(source.IsColumnVisible(srcX2));
                        Debug.Assert(source.IsColumnVisible(srcX3));
                        Debug.Assert(source.IsColumnVisible(srcX4));
#endif

                        ColorBgra *p1 = src1 + srcX1;
                        ColorBgra *p2 = src2 + srcX2;
                        ColorBgra *p3 = src3 + srcX3;
                        ColorBgra *p4 = src4 + srcX4;

                        int r = (2 + p1->R + p2->R + p3->R + p4->R) >> 2;
                        int g = (2 + p1->G + p2->G + p3->G + p4->G) >> 2;
                        int b = (2 + p1->B + p2->B + p3->B + p4->B) >> 2;
                        int a = (2 + p1->A + p2->A + p3->A + p4->A) >> 2;

                        // Blend it over the checkerboard background
                        int v = ((checkerX ^ checkerY) & 8) * 8 + 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;

                        dstPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + 0xff000000;
                        ++dstPtr;
                    }
                }
            }
        }
Пример #17
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;
                        }
                    }
                }
            }
        }
Пример #18
0
        /// <summary>
        /// Fits the source surface to this surface using nearest neighbor resampling.
        /// </summary>
        /// <param name="source">The surface to read pixels from.</param>
        /// <param name="dstRoi">The rectangle to clip rendering to.</param>
        public void NearestNeighborFitSurface(Surface source, Rectangle dstRoi)
        {
            Rectangle roi = Rectangle.Intersect(dstRoi, this.Bounds);

            unsafe
            {
                for (int dstY = roi.Top; dstY < roi.Bottom; ++dstY)
                {
                    int srcY = (dstY * source.height) / height;
                    ColorBgra *srcRow = source.GetRowAddressUnchecked(srcY);
                    ColorBgra *dstPtr = this.GetPointAddressUnchecked(roi.Left, dstY);

                    for (int dstX = roi.Left; dstX < roi.Right; ++dstX)
                    {
                        int srcX = (dstX * source.width) / width;
                        *dstPtr = *(srcRow + srcX);
                        ++dstPtr;
                    }
                }
            }
        }
Пример #19
0
        /// <summary>
        /// Copies the contents of the given surface to the upper left corner of this surface.
        /// </summary>
        /// <param name="source">The surface to copy pixels from.</param>
        /// <remarks>
        /// 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)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("Surface");
            }

            if (this.stride == source.stride &&
                (this.width * ColorBgra.SizeOf) == this.stride &&
                this.width == source.width &&
                this.height == source.height)
            {
                unsafe
                {
                    Memory.Copy(this.scan0.VoidStar,
                                source.scan0.VoidStar,
                                ((ulong)(height - 1) * (ulong)stride) + ((ulong)width * (ulong)ColorBgra.SizeOf));
                }
            }
            else
            {
                int copyWidth = Math.Min(width, source.width);
                int copyHeight = Math.Min(height, source.height);

                unsafe
                {
                    for (int y = 0; y < copyHeight; ++y)
                    {
                        Memory.Copy(GetRowAddressUnchecked(y), source.GetRowAddressUnchecked(y), (ulong)copyWidth * (ulong)ColorBgra.SizeOf);
                    }
                }
            }
        }
Пример #20
0
        /// <summary>
        /// Implements bicubic filtering with NO bounds checking at any pixel.
        /// </summary>
        public void BicubicFitSurfaceUnchecked(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 = 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);
                        }

                        rColCache = (double*)rColCacheIP.ToPointer();
                        ColorBgra *srcRowPtr = source.GetRowAddressUnchecked(srcRowInt - 1);

                        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;

                            ColorBgra *srcPtr = srcRowPtr + srcColumnInt - 1;
                            for (int n = 0; n <= 3; ++n)
                            {
                                double w0 = rColCache[0] * rRowCache[n];
                                double w1 = rColCache[1] * rRowCache[n];
                                double w2 = rColCache[2] * rRowCache[n];
                                double w3 = rColCache[3] * rRowCache[n];

                                double a0 = srcPtr[0].A;
                                double a1 = srcPtr[1].A;
                                double a2 = srcPtr[2].A;
                                double a3 = srcPtr[3].A;

                                alphaSum += (a0 * w0) + (a1 * w1) + (a2 * w2) + (a3 * w3);
                                totalWeight += w0 + w1 + w2 + w3;

                                blueSum += (a0 * srcPtr[0].B * w0) + (a1 * srcPtr[1].B * w1) + (a2 * srcPtr[2].B * w2) + (a3 * srcPtr[3].B * w3);
                                greenSum += (a0 * srcPtr[0].G * w0) + (a1 * srcPtr[1].G * w1) + (a2 * srcPtr[2].G * w2) + (a3 * srcPtr[3].G * w3);
                                redSum += (a0 * srcPtr[0].R * w0) + (a1 * srcPtr[1].R * w1) + (a2 * srcPtr[2].R * w2) + (a3 * srcPtr[3].R * w3);

                                srcPtr = (ColorBgra *)((byte *)srcPtr + 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;
                            rColCache += 4;
                        } // for (dstX...
                    } // for (dstY...

                    Memory.Free(rColCacheIP);
                } // unsafe
            }
        }