public void Draw(GraphicsHandler graphics, RectangleF rect) { var outerRadius = Radius.Width; var yscale = Radius.Height / Radius.Width; var center = Center; var origin = GradientOrigin; var scale = 1f; if (wrap != GradientWrapMode.Pad) { // use eto's transformrectangle as it'll make the rect encompass the resulting transformed area var boundRect = transform.Invert().ToEto().TransformRectangle(rect); // find max number of iterations we need to fill the bounding rectangle scale = GradientHelper.GetRadialScale(Center, Radius, GradientOrigin, boundRect); } if (Gradient == null || scale > lastScale) { var stops = GradientHelper.GetGradientStops(StartColor.ToCG(), EndColor.ToCG(), scale, wrap).ToList(); lastScale = scale; Gradient = new CGGradient(CGColorSpace.CreateDeviceRGB(), stops.Select(r => r.Item2).ToArray(), stops.Select(r => (nfloat)r.Item1).ToArray()); } else { scale = lastScale; } var scaledRect = new RectangleF(GradientOrigin - (GradientOrigin - Center + Radius) * scale, GradientOrigin + (Center + Radius - GradientOrigin) * scale); center = scaledRect.Center; outerRadius *= scale; // adjust center based on ellipse scale from gradient origin center.Y = origin.Y - (origin.Y - center.Y) / yscale; // scale to draw elliptical gradient var t = new CGAffineTransform(1, 0f, 0f, yscale, 0, origin.Y - origin.Y * yscale); t.Multiply(transform); graphics.Control.SaveState(); graphics.Control.ConcatCTM(t); graphics.Control.DrawRadialGradient(Gradient, origin.ToNS(), 0, center.ToNS(), outerRadius, CGGradientDrawingOptions.DrawsAfterEndLocation | CGGradientDrawingOptions.DrawsBeforeStartLocation); graphics.Control.RestoreState(); }
public Matrix(RectangleF rect, PointF[] plgpts) { if (plgpts == null) throw new ArgumentNullException ("plgpts"); if (plgpts.Length != 3) throw new ArgumentException ("plgpts"); PointF p0 = plgpts [0]; PointF p1 = plgpts [1]; PointF p2 = plgpts [2]; float m11 = (p1.X - p0.X) / rect.Width; float m12 = (p1.Y - p0.Y) / rect.Width; float m21 = (p2.X - p0.X) / rect.Height; float m22 = (p2.Y - p0.Y) / rect.Height; transform = CGAffineTransform.MakeTranslation(-rect.X, -rect.Y); transform.Multiply(new CGAffineTransform (m11, m12, m21, m22, p0.X, p0.Y)); }
/// <summary> /// Draws the specified portion of the specified Image at the specified location and with the specified size. /// /// The destPoints specifies a parallelogram with the first point specifying the upper left corner, /// second point specifying the upper right corner and the third point specifying the lower left corner. /// /// The srcRect parameter specifies a rectangular portion of the image object to draw. This portion is scaled /// up or down (in the case where source rectangle overruns the bounds of the image) to fit inside the rectangle /// specified by the destRect parameter. /// </summary> /// <param name="image">Image.</param> /// <param name="destPoints">Destination points.</param> /// <param name="srcRect">Source rect.</param> /// <param name="srcUnit">Source unit.</param> public void DrawImage(Image image, PointF [] destPoints, RectangleF srcRect, GraphicsUnit srcUnit) { if (image == null) throw new ArgumentNullException ("image"); if (destPoints == null) throw new ArgumentNullException ("destPoints"); if (destPoints.Length < 3) throw new ArgumentException ("Destination points must be an array with a length of 3 or 4. " + "A length of 3 defines a parallelogram with the upper-left, upper-right, " + "and lower-left corners. A length of 4 defines a quadrilateral with the " + "fourth element of the array specifying the lower-right coordinate."); // Windows throws a Not Implemented error if the points are more than 3 if (destPoints.Length > 3) throw new NotImplementedException (); var srcRect1 = srcRect; // If the source units are not the same we need to convert them // The reason we check for Pixel here is that our graphics already has the Pixel's baked into the model view transform if (srcUnit != graphicsUnit && srcUnit != GraphicsUnit.Pixel) { ConversionHelpers.GraphicsUnitConversion (srcUnit, graphicsUnit, image.HorizontalResolution, image.VerticalResolution, ref srcRect1); } // Obtain the subImage var subImage = image.NativeCGImage.WithImageInRect (srcRect1); // If we do not have anything to draw then we exit here if (subImage.Width == 0 || subImage.Height == 0) return; // create our rectangle. Offset is 0 because the CreateGeometricTransform bakes our x,y offset in there. var rect = new RectangleF (0,0, destPoints [1].X - destPoints [0].X, destPoints [2].Y - destPoints [0].Y); // We need to flip our Y axis so the image appears right side up var geoTransform = new CGAffineTransform (1, 0, 0, -1, 0, rect.Height); // Make sure we scale the image in case the source rectangle // overruns our subimage bounds (width and/or height) float scaleX = subImage.Width/srcRect1.Width; float scaleY = subImage.Height/srcRect1.Height; geoTransform.Scale (scaleX, scaleY); //var geott = GeomUtilities.CreateGeometricTransform (rect, destPoints); geoTransform.Multiply (GeomUtilities.CreateGeometricTransform (rect, destPoints)); // Apply our transform to the context context.ConcatCTM (geoTransform); // now we draw our image. context.DrawImage(rect, subImage); // Now we revert our image transform from the context var revert = CGAffineTransform.CGAffineTransformInvert (geoTransform); context.ConcatCTM (revert); }
public void Shear(float shearX, float shearY, MatrixOrder order) { var affine = new CGAffineTransform (1, shearY, shearX, 1, 0, 0); if (order == MatrixOrder.Append) transform.Multiply (affine); else { affine.Multiply (transform); transform = affine; } }
/// <summary> /// Draws the specified Image at the specified location and with the specified shape and size. /// /// The destPoints parameter specifies three points of a parallelogram. The three PointF structures /// represent the upper-left, upper-right, and lower-left corners of the parallelogram. The fourth point /// is extrapolated from the first three to form a parallelogram. /// /// The image represented by the image object is scaled and sheared to fit the shape of the parallelogram /// specified by the destPoints parameter. /// </summary> /// <param name="image">Image.</param> /// <param name="destPoints">Destination points.</param> public void DrawImage(Image image, PointF [] destPoints) { if (image == null) throw new ArgumentNullException ("image"); if (destPoints == null) throw new ArgumentNullException ("destPoints"); if (destPoints.Length < 3) throw new ArgumentException ("Destination points must be an array with a length of 3 or 4. " + "A length of 3 defines a parallelogram with the upper-left, upper-right, " + "and lower-left corners. A length of 4 defines a quadrilateral with the " + "fourth element of the array specifying the lower-right coordinate."); // Windows throws a Not Implemented error if the points are more than 3 if (destPoints.Length > 3) throw new NotImplementedException (); // create our rectangle. Offset is 0 because the CreateGeometricTransform bakes our x,y offset in there. var rect = new RectangleF (0,0, destPoints [1].X - destPoints [0].X, destPoints [2].Y - destPoints [0].Y); // We need to flip our Y axis so the image appears right side up var geoTransform = new CGAffineTransform (1, 0, 0, -1, 0, rect.Height); //var geott = GeomUtilities.CreateGeometricTransform (rect, destPoints); geoTransform.Multiply (GeomUtilities.CreateGeometricTransform (rect, destPoints)); // Apply our transform to the context context.ConcatCTM (geoTransform); // now we draw our image. context.DrawImage(rect, image.NativeCGImage); // Now we revert our image transform from the context var revert = CGAffineTransform.CGAffineTransformInvert (geoTransform); context.ConcatCTM (revert); }