internal new void RotateFlip(RotateFlipType rotateFlipType) { CGAffineTransform rotateFlip = CGAffineTransform.MakeIdentity(); int width, height; width = (int)NativeCGImage.Width; height = (int)NativeCGImage.Height; switch (rotateFlipType) { // case RotateFlipType.RotateNoneFlipNone: // //case RotateFlipType.Rotate180FlipXY: // rotateFlip = GeomUtilities.CreateRotateFlipTransform (b.Width, b.Height, 0, false, false); // break; case RotateFlipType.Rotate90FlipNone: //case RotateFlipType.Rotate270FlipXY: rotateFlip = GeomUtilities.CreateRotateFlipTransform(ref width, ref height, 90, false, false); break; case RotateFlipType.Rotate180FlipNone: //case RotateFlipType.RotateNoneFlipXY: rotateFlip = GeomUtilities.CreateRotateFlipTransform(ref width, ref height, 0, true, true); break; case RotateFlipType.Rotate270FlipNone: //case RotateFlipType.Rotate90FlipXY: rotateFlip = GeomUtilities.CreateRotateFlipTransform(ref width, ref height, 270, false, false); break; case RotateFlipType.RotateNoneFlipX: //case RotateFlipType.Rotate180FlipY: rotateFlip = GeomUtilities.CreateRotateFlipTransform(ref width, ref height, 0, true, false); break; case RotateFlipType.Rotate90FlipX: //case RotateFlipType.Rotate270FlipY: rotateFlip = GeomUtilities.CreateRotateFlipTransform(ref width, ref height, 90, true, false); break; case RotateFlipType.Rotate180FlipX: //case RotateFlipType.RotateNoneFlipY: rotateFlip = GeomUtilities.CreateRotateFlipTransform(ref width, ref height, 0, false, true); break; case RotateFlipType.Rotate270FlipX: //case RotateFlipType.Rotate90FlipY: rotateFlip = GeomUtilities.CreateRotateFlipTransform(ref width, ref height, 270, true, false); break; } var bytesPerRow = (width * (int)NativeCGImage.BitsPerPixel + 7) / 8; var newBitmapBlock = Marshal.AllocHGlobal(height * bytesPerRow); var newBitmapContext = new CGBitmapContext(newBitmapBlock, width, height, NativeCGImage.BitsPerComponent, bytesPerRow, NativeCGImage.ColorSpace, NativeCGImage.AlphaInfo); newBitmapContext.ConcatCTM(rotateFlip); newBitmapContext.DrawImage(new CGRect(0, 0, NativeCGImage.Width, NativeCGImage.Height), NativeCGImage); newBitmapContext.Flush(); // If the width or height is not the seme we need to switch the dpiHeight and dpiWidth // We should be able to get around this with set resolution later. if (NativeCGImage.Width != width || NativeCGImage.Height != height) { var temp = dpiWidth; dpiHeight = dpiWidth; dpiWidth = temp; } physicalDimension.Width = (float)width; physicalDimension.Height = (float)height; physicalSize = new SizeF(physicalDimension.Width, physicalDimension.Height); physicalSize.Width *= ConversionHelpers.MS_DPI / dpiWidth; physicalSize.Height *= ConversionHelpers.MS_DPI / dpiHeight; // In windows the RawFormat is changed to MemoryBmp to show that the image has changed. rawFormat = ImageFormat.MemoryBmp; // Set our transform for this image for the new height imageTransform = new CGAffineTransform(1, 0, 0, -1, 0, height); // bitmapBlock is owned by dataProvider and freed implicitly if (dataProvider != null) { dataProvider.Dispose(); } if (cachedContext != null) { cachedContext.Dispose(); } NativeCGImage.Dispose(); this.bitmapBlock = newBitmapBlock; this.dataProvider = new CGDataProvider(bitmapBlock, height * bytesPerRow); this.NativeCGImage = newBitmapContext.ToImage(); this.cachedContext = newBitmapContext; this.imageSource = null; // update the cached size imageSize.Width = this.Width; imageSize.Height = this.Height; }
/// <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.ToCGRect()); // 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.ToCGRect(), subImage); // Now we revert our image transform from the context var revert = CGAffineTransform.CGAffineTransformInvert(geoTransform); context.ConcatCTM(revert); }