Example #1
0
        public IrregularSurface(Cairo.ImageSurface source, Rectangle[] roi)
        {
            this.placedSurfaces = new List<PlacedSurface> (roi.Length);

            foreach (Rectangle rect in roi) {
                Rectangle ri = Rectangle.Intersect (source.GetBounds (), rect);

                if (!ri.IsEmpty)
                    this.placedSurfaces.Add (new PlacedSurface (source, ri));
            }

            this.region = Utility.RectanglesToRegion (roi);
            this.region.Intersect (Region.Rectangle (source.GetBounds ()));
        }
Example #2
0
        /// <summary>
        /// Constructs an IrregularSurface by copying the given region-of-interest from an Image.
        /// </summary>
        /// <param name="source">The Surface to copy pixels from.</param>
        /// <param name="roi">Defines the Region from which to copy pixels from the Image.</param>
        public IrregularSurface(Cairo.ImageSurface source, Region roi)
        {
            Region roiClipped = (Region)roi.Copy ();
            roiClipped.Intersect (Region.Rectangle (source.GetBounds ()));

            Rectangle[] rects = roiClipped.GetRectangles ();
            this.placedSurfaces = new List<PlacedSurface> (rects.Length);

            foreach (Rectangle rect in rects)
                this.placedSurfaces.Add (new PlacedSurface (source, rect));

            this.region = roiClipped;
        }
Example #3
0
		/// <summary>
		/// Provides a default implementation for performing dst = F(lhs, rhs) over some rectangle of interest.
		/// </summary>
		/// <param name="dst">The Surface to write pixels to.</param>
		/// <param name="dstOffset">The pixel offset that defines the upper-left of the rectangle-of-interest for the dst Surface.</param>
		/// <param name="lhs">The Surface to read pixels from for the lhs parameter given to the method <b>ColorBgra Apply(ColorBgra, ColorBgra)</b>.</param>
		/// <param name="lhsOffset">The pixel offset that defines the upper-left of the rectangle-of-interest for the lhs Surface.</param>
		/// <param name="rhs">The Surface to read pixels from for the rhs parameter given to the method <b>ColorBgra Apply(ColorBgra, ColorBgra)</b></param>
		/// <param name="rhsOffset">The pixel offset that defines the upper-left of the rectangle-of-interest for the rhs Surface.</param>
		/// <param name="roiSize">The size of the rectangles-of-interest for all Surfaces.</param>
		public void Apply (Cairo.ImageSurface dst, Point dstOffset,
				  Cairo.ImageSurface lhs, Point lhsOffset,
				  Cairo.ImageSurface rhs, Point rhsOffset,
				  Size roiSize)
		{
			// Bounds checking only enabled in Debug builds.
#if DEBUG
			// Create bounding rectangles for each Surface
			Rectangle dstRect = new Rectangle (dstOffset, roiSize);
			Rectangle lhsRect = new Rectangle (lhsOffset, roiSize);
			Rectangle rhsRect = new Rectangle (rhsOffset, roiSize);

			// Clip those rectangles to those Surface's bounding rectangles
			Rectangle dstClip = Rectangle.Intersect (dstRect, dst.GetBounds ());
			Rectangle lhsClip = Rectangle.Intersect (lhsRect, lhs.GetBounds ());
			Rectangle rhsClip = Rectangle.Intersect (rhsRect, rhs.GetBounds ());

			// If any of those Rectangles actually got clipped, then throw an exception
			if (dstRect != dstClip) {
				throw new ArgumentOutOfRangeException ("roiSize", "Destination roi out of bounds");
			}

			if (lhsRect != lhsClip) {
				throw new ArgumentOutOfRangeException ("roiSize", "lhs roi out of bounds");
			}

			if (rhsRect != rhsClip) {
				throw new ArgumentOutOfRangeException ("roiSize", "rhs roi out of bounds");
			}
#endif

			// Cache the width and height properties
			int width = roiSize.Width;
			int height = roiSize.Height;

			// Do the work.
			unsafe {
				for (int row = 0; row < height; ++row) {
					ColorBgra* dstPtr = dst.GetPointAddress (dstOffset.X, dstOffset.Y + row);
					ColorBgra* lhsPtr = lhs.GetPointAddress (lhsOffset.X, lhsOffset.Y + row);
					ColorBgra* rhsPtr = rhs.GetPointAddress (rhsOffset.X, rhsOffset.Y + row);

					Apply (dstPtr, lhsPtr, rhsPtr, width);
				}
			}
		}
Example #4
0
		public void Render (List<Layer> layers, Cairo.ImageSurface dst, Gdk.Point offset)
		{
			dst.Flush ();

            // Our rectangle of interest
            var r = new Gdk.Rectangle (offset, dst.GetBounds ().Size).ToCairoRectangle ();

            using (var g = new Cairo.Context (dst)) {
                // Create the transparent checkerboard background
                g.Translate (-offset.X, -offset.Y);
                g.FillRectangle (r, tranparent_pattern, new Cairo.PointD (offset.X, offset.Y));

                for (var i = 0; i < layers.Count; i++) {
                    var layer = layers[i];

                    // If we're in LivePreview, substitute current layer with the preview layer
                    if (layer == PintaCore.Layers.CurrentLayer && PintaCore.LivePreview.IsEnabled)
                        layer = CreateLivePreviewLayer (layer);

                    // If the layer is offset, handle it here
                    if (!layer.Transform.IsIdentity ())
                        layer = CreateOffsetLayer (layer);

                    // No need to resize the surface if we're at 100% zoom
                    if (scale_factor.Ratio == 1)
                        layer.Draw (g, layer.Surface, layer.Opacity, false);
                    else {
                        using (var scaled = new Cairo.ImageSurface (Cairo.Format.Argb32, dst.Width, dst.Height)) {
                            g.Save ();
                            // Have to undo the translate set above
                            g.Translate (offset.X, offset.Y);
                            CopyScaled (layer.Surface, scaled, r.ToGdkRectangle ());
                            layer.Draw (g, scaled, layer.Opacity, false);
                            g.Restore ();
                        }
                    }
                }
            }

            // If we are at least 200% and grid is requested, draw it
            if (enable_pixel_grid && PintaCore.Actions.View.PixelGrid.Active && scale_factor.Ratio <= 0.5d)
                RenderPixelGrid (dst, offset);
			
			dst.MarkDirty ();
		}
Example #5
0
        private unsafe void RenderOneToOne(List<Layer> layers, Cairo.ImageSurface dst, Gdk.Point offset)
        {
            // The first layer should be blended with the transparent checkerboard
            var checker = true;
            CheckerBoardOperation checker_op = null;

            for (int i = 0; i < layers.Count; i++) {
                var layer = layers[i];

                // If we're in LivePreview, substitute current layer with the preview layer
                if (layer == PintaCore.Layers.CurrentLayer && PintaCore.LivePreview.IsEnabled)
                    layer = CreateLivePreviewLayer (layer);

                // If the layer is offset, handle it here
                if (!layer.Transform.IsIdentity ())
                    layer = CreateOffsetLayer (layer);

                var src = layer.Surface;

                // Get the blend mode for this layer and opacity
                var blend_op = UserBlendOps.GetBlendOp (layer.BlendMode, layer.Opacity);

                if (checker)
                    checker_op = new CheckerBoardOperation (layer.Opacity);

                // Figure out where our source and destination intersect
                var srcRect = new Gdk.Rectangle (offset, dst.GetBounds ().Size);
                srcRect.Intersect (src.GetBounds ());

                // Get pointers to our surfaces
                var src_ptr = (ColorBgra*)src.DataPtr;
                var dst_ptr = (ColorBgra*)dst.DataPtr;

                // Cache widths
                int src_width = src.Width;
                int dst_width = dst.Width;

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

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

                    while (dstCol < dstColEnd) {
                        // Blend it over the checkerboard background
                        if (checker)
                            *dstRowPtr = checker_op.Apply (*srcRowPtr, dstCol, checkerY);
                        else
                            *dstRowPtr = blend_op.Apply (*dstRowPtr, *srcRowPtr);

                        ++dstRowPtr;
                        ++srcRowPtr;
                        ++dstCol;
                    }
                }

                // Only checker the first layer
                checker = false;
            }
        }
Example #6
0
        private unsafe void RenderZoomOut(Cairo.ImageSurface src, Cairo.ImageSurface dst, Gdk.Point offset, Gdk.Size destinationSize, bool checker)
        {
            const int fpShift = 12;
            const int fpFactor = (1 << fpShift);

            Gdk.Size sourceSize = src.GetBounds ().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;

            ColorBgra* src_ptr = (ColorBgra*)src.DataPtr;
            ColorBgra* dst_ptr = (ColorBgra*)dst.DataPtr;
            int src_width = src.Width;
            int dst_width = dst.Width;

            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

                ColorBgra* src1 = src.GetRowAddressUnchecked (src_ptr, src_width, srcY1);
                ColorBgra* src2 = src.GetRowAddressUnchecked (src_ptr, src_width, srcY2);
                ColorBgra* src3 = src.GetRowAddressUnchecked (src_ptr, src_width, srcY3);
                ColorBgra* src4 = src.GetRowAddressUnchecked (src_ptr, src_width, srcY4);
                ColorBgra* dstPtr = dst.GetRowAddressUnchecked (dst_ptr, dst_width, 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
                    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;

                    if (checker) {
                        // 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;
                    } else {
                        dstPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)a << 24);
                    }

                    ++dstPtr;
                }
            }
        }
Example #7
0
        private unsafe void RenderOneToOne(Cairo.ImageSurface src, Cairo.ImageSurface dst, Gdk.Point offset, bool checker)
        {
            Gdk.Rectangle srcRect = new Gdk.Rectangle (offset, dst.GetBounds ().Size);
            srcRect.Intersect (src.GetBounds ());

            ColorBgra* src_ptr = (ColorBgra*)src.DataPtr;
            ColorBgra* dst_ptr = (ColorBgra*)dst.DataPtr;

            int src_width = src.Width;
            int dst_width = dst.Width;
            int dst_height = dst.Height;

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

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

                while (dstCol < dstColEnd) {
                    // Blend it over the checkerboard background
                    if (checker) {
                        int b = srcRowPtr->B;
                        int g = srcRowPtr->G;
                        int r = srcRowPtr->R;
                        int a = srcRowPtr->A;

                        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);
                    } else {
                        *dstRowPtr = *srcRowPtr;
                    }

                    ++dstRowPtr;
                    ++srcRowPtr;
                    ++dstCol;
                }
            }
        }
Example #8
0
        private unsafe void CopyScaledZoomOut (Cairo.ImageSurface src, Cairo.ImageSurface dst, Rectangle roi)
        {
            // Tell Cairo we need the latest raw data
            dst.Flush ();

            const int fpShift = 12;
            const int fpFactor = (1 << fpShift);

            var source_size = src.GetBounds ().Size;

            // Find destination bounds
            var dst_left = (int)(((long)roi.X * fpFactor * (long)source_size.Width) / (long)destination_size.Width);
            var dst_top = (int)(((long)roi.Y * fpFactor * (long)source_size.Height) / (long)destination_size.Height);
            var dst_right = (int)(((long)(roi.X + dst.Width) * fpFactor * (long)source_size.Width) / (long)destination_size.Width);
            var dst_bottom = (int)(((long)(roi.Y + dst.Height) * fpFactor * (long)source_size.Height) / (long)destination_size.Height);
            var dx = (dst_right - dst_left) / dst.Width;
            var dy = (dst_bottom - dst_top) / dst.Height;

            // Cache pointers to surface raw data and sizes
            var src_ptr = (ColorBgra*)src.DataPtr;
            var dst_ptr = (ColorBgra*)dst.DataPtr;
            var src_width = src.Width;
            var dst_width = dst.Width;
            var dst_height = dst.Height;

            for (int dstRow = 0, fDstY = dst_top; dstRow < dst_height && fDstY < dst_bottom; ++dstRow, fDstY += dy) {
                var srcY1 = fDstY >> fpShift;                            // y
                var srcY2 = (fDstY + (dy >> 2)) >> fpShift;              // y + 0.25
                var srcY3 = (fDstY + (dy >> 1)) >> fpShift;              // y + 0.50
                var srcY4 = (fDstY + (dy >> 1) + (dy >> 2)) >> fpShift;  // y + 0.75

                var src1 = src.GetRowAddressUnchecked (src_ptr, src_width, srcY1);
                var src2 = src.GetRowAddressUnchecked (src_ptr, src_width, srcY2);
                var src3 = src.GetRowAddressUnchecked (src_ptr, src_width, srcY3);
                var src4 = src.GetRowAddressUnchecked (src_ptr, src_width, srcY4);
                var dstPtr = dst.GetRowAddressUnchecked (dst_ptr, dst_width, dstRow);

                var checkerY = dstRow + roi.Y;
                var checkerX = roi.X;
                var maxCheckerX = checkerX + dst.Width;

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

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

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

                    // Copy color to destination
                    *dstPtr++ = ColorBgra.FromUInt32 ((uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)a << 24));
                }
            }

            // Tell Cairo we changed the raw data
            dst.MarkDirty ();
        }