public void SetPixel(int x, int y, Color color) { if (x < 0 || x > NativeCGImage.Width - 1) { throw new InvalidEnumArgumentException("Parameter must be positive and < Width."); } if (y < 0 || y > NativeCGImage.Height - 1) { throw new InvalidEnumArgumentException("Parameter must be positive and < Height."); } if (cachedContext == null || cachedContext.Handle == IntPtr.Zero) { GetRenderableContext(); } // We are going to cheat here by drawing directly to the cached context that is // associated to the image. This way we do not have to play with pixels and offsets // to change the data. If this proves to be non performant then we will change it later. cachedContext.SaveState(); cachedContext.ConcatCTM(cachedContext.GetCTM().Invert()); cachedContext.ConcatCTM(imageTransform); cachedContext.SetFillColor(color); cachedContext.FillRect(new CGRect(x, y, 1, 1)); cachedContext.FillPath(); cachedContext.RestoreState(); }
/// <summary> /// Renders the image given the specified parameters. /// </summary> /// <param name="components">Number of components.</param> /// <param name="flipX">Flip image in X direction?</param> /// <param name="flipY">Flip image in Y direction?</param> /// <param name="rotation">Image rotation.</param> public override void Render(int components, bool flipX, bool flipY, int rotation) { // Switch R and B components before rendering. var length = SizeOfRgba * this.width * this.height; var bytes = new byte[length]; Marshal.Copy(this.pixels.Pointer, bytes, 0, length); for (var k = 0; k < length; k += 4) { var tmp = bytes[k]; bytes[k] = bytes[k + 2]; bytes[k + 2] = tmp; } using ( var context = new CGBitmapContext( bytes, this.width, this.height, 8, SizeOfRgba * this.width, CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedLast)) { var transform = CGAffineTransform.MakeRotation((float)(rotation * Math.PI / 180.0)); transform.Scale(flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f); transform.Translate(flipX ? this.width : 0.0f, flipY ? this.height : 0.0f); context.ConcatCTM(transform); this.image = context.ToImage(); } }
// Draws our animation path on the background image, just to show it void DrawPathAsBackground() { // create our offscreen bitmap context var bitmapSize = new CGSize(View.Frame.Size); using (var context = new CGBitmapContext( IntPtr.Zero, (int)bitmapSize.Width, (int)bitmapSize.Height, 8, (int)(4 * bitmapSize.Width), CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedFirst)) { // convert to View space var affineTransform = CGAffineTransform.MakeIdentity(); // invert the y axis affineTransform.Scale(1f, -1f); // move the y axis up affineTransform.Translate(0, View.Frame.Height); context.ConcatCTM(affineTransform); // actually draw the path context.AddPath(animationPath); context.SetStrokeColor(UIColor.LightGray.CGColor); context.SetLineWidth(3f); context.StrokePath(); // set what we've drawn as the backgound image backgroundImage.Image = UIImage.FromImage(context.ToImage()); } }
/// <summary> /// Draws our animation path on the background image, just to show it /// </summary> protected void DrawPathAsBackground() { //---- create our offscreen bitmap context // size SizeF bitmapSize = new SizeF(this.View.Frame.Size); using (CGBitmapContext context = new CGBitmapContext(IntPtr.Zero , (int)bitmapSize.Width, (int)bitmapSize.Height, 8 , (int)(4 * bitmapSize.Width), CGColorSpace.CreateDeviceRGB() , CGImageAlphaInfo.PremultipliedFirst)) { //---- convert to View space CGAffineTransform affineTransform = CGAffineTransform.MakeIdentity(); //---- invert the y axis affineTransform.Scale(1, -1); //---- move the y axis up affineTransform.Translate(0, this.View.Frame.Height); context.ConcatCTM(affineTransform); //---- actually draw the path context.AddPath(this._animationPath); context.SetStrokeColorWithColor(UIColor.LightGray.CGColor); context.SetLineWidth(3); context.StrokePath(); //---- set what we've drawn as the backgound image this._backgroundImage.Image = UIImage.FromImage(context.ToImage()); } }
public static XIR.Image RemoteRepresentation(this NSAttributedString attributedString) { var typesetter = new CTTypesetter(attributedString); var measure = CGSize.Empty; var count = typesetter.SuggestLineBreak(0, 8388608); var line = typesetter.GetLine(new NSRange(0, count)); // Create and initialize some values from the bounds. nfloat ascent; nfloat descent; nfloat leading; var lineWidth = line.GetTypographicBounds(out ascent, out descent, out leading); measure.Height += (float)Math.Ceiling(ascent + descent + leading + 1); // +1 matches best to CTFramesetter's behavior measure.Width = (float)lineWidth; var width = (int)measure.Width > 0 ? (int)measure.Width : 200; var height = (int)measure.Height > 0 ? (int)measure.Height : 200; var bytesPerRow = width * 4; using (var context = new CGBitmapContext( IntPtr.Zero, width, height, 8, bytesPerRow, CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedFirst)) { context.ConcatCTM(context.GetCTM().Invert()); var matrix = new CGAffineTransform( 1, 0, 0, -1, 0, height); context.ConcatCTM(matrix); var textMatrix = new CGAffineTransform( 1, 0, 0, -1, 0, ascent); context.TextMatrix = textMatrix; line.Draw(context); line.Dispose(); return(RemoteRepresentation(context)); } }
public static void BeginImageContextWithOptions(CGSize size, bool opaque, nfloat scale) { // Create new image context ColorSpace = CGColorSpace.CreateDeviceRGB (); Context = new CGBitmapContext (null, (int)size.Width, (int)size.Height, 8, 0, ColorSpace, CGImageAlphaInfo.PremultipliedLast); // Flip context vertically var flipVertical = new CGAffineTransform(1,0,0,-1,0,size.Height); Context.ConcatCTM (flipVertical); // Save previous context ImageSize = size; PreviousContext = NSGraphicsContext.CurrentContext; NSGraphicsContext.CurrentContext = NSGraphicsContext.FromCGContext (Context, true); }
public static void BeginImageContextWithOptions(CGSize size, bool opaque, nfloat scale) { // Create new image context ColorSpace = CGColorSpace.CreateDeviceRGB(); Context = new CGBitmapContext(null, (int)size.Width, (int)size.Height, 8, 0, ColorSpace, CGImageAlphaInfo.PremultipliedLast); // Flip context vertically var flipVertical = new CGAffineTransform(1, 0, 0, -1, 0, size.Height); Context.ConcatCTM(flipVertical); // Save previous context ImageSize = size; PreviousContext = NSGraphicsContext.CurrentContext; NSGraphicsContext.CurrentContext = NSGraphicsContext.FromCGContext(Context, true); }
/// <summary> /// Returns thumb image object for page /// </summary> /// <param name="thumbContentSize">Thumb content size</param> /// <param name="pageNumber">Page number for what will created image object</param> /// <returns>Page image object</returns> private static UIImage GetThumbImage(float thumbContentSize, int pageNumber) { if ((pageNumber <= 0) || (pageNumber > PDFDocument.PageCount)) { return(null); } // Calc page view size var pageSize = PageContentView.GetPageViewSize(pageNumber); if (pageSize.Width % 2 > 0) { pageSize.Width--; } if (pageSize.Height % 2 > 0) { pageSize.Height--; } // Calc target size var targetSize = new Size((int)pageSize.Width, (int)pageSize.Height); // Draw page on CGImage CGImage pageImage; using (CGColorSpace rgb = CGColorSpace.CreateDeviceRGB()) { using (var context = new CGBitmapContext(null, targetSize.Width, targetSize.Height, 8, 0, rgb, CGBitmapFlags.ByteOrder32Little | CGBitmapFlags.NoneSkipFirst)) { using (var pdfPage = PDFDocument.GetPage(pageNumber)) { // Draw page on custom CGBitmap context var thumbRect = new RectangleF(0.0f, 0.0f, targetSize.Width, targetSize.Height); context.SetFillColor(1.0f, 1.0f, 1.0f, 1.0f); context.FillRect(thumbRect); context.ConcatCTM(pdfPage.GetDrawingTransform(CGPDFBox.Crop, thumbRect, 0, true)); context.SetRenderingIntent(CGColorRenderingIntent.Default); context.InterpolationQuality = CGInterpolationQuality.Default; context.DrawPDFPage(pdfPage); // Create CGImage from custom CGBitmap context pageImage = context.ToImage(); } } } return(UIImage.FromImage(pageImage)); }
protected override void UpdateCapturedImage() { if (view != null && layer == null) { var bitmap = view.BitmapImageRepForCachingDisplayInRect(view.Bounds); if (bitmap == null) { return; } view.CacheDisplay(view.Bounds, bitmap); var data = bitmap.RepresentationUsingTypeProperties(NSBitmapImageFileType.Png); CapturedImage = data.ToArray(); } else if (layer != null) { var scale = layer.ContentsScale; nint h = (nint)(layer.Bounds.Height * scale); nint w = (nint)(layer.Bounds.Width * scale); nint bytesPerRow = w * 4; if (h <= 0 || w <= 0) { return; } using (var colorSpace = CGColorSpace.CreateGenericRgb()) using (var context = new CGBitmapContext(IntPtr.Zero, w, h, 8, bytesPerRow, colorSpace, CGImageAlphaInfo.PremultipliedLast)) { // Apply a flipping transform because layers are apparently weird. var transform = new CGAffineTransform(scale, 0, 0, -scale, 0, h); context.ConcatCTM(transform); layer.RenderInContext(context); using (var image = context.ToImage()) using (var bitmap = new NSBitmapImageRep(image)) { var data = bitmap.RepresentationUsingTypeProperties(NSBitmapImageFileType.Png); CapturedImage = data.ToArray(); } } } }
/// <summary> /// Renders the image given the specified parameters. /// </summary> /// <param name="components">Number of components.</param> /// <param name="flipX">Flip image in X direction?</param> /// <param name="flipY">Flip image in Y direction?</param> /// <param name="rotation">Image rotation.</param> public override void Render(int components, bool flipX, bool flipY, int rotation) { using ( var context = new CGBitmapContext( this.pixels.Pointer, this.width, this.height, 8, 4 * this.width, CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedLast)) { var transform = CGAffineTransform.MakeRotation((float)(rotation * Math.PI / 180.0)); transform.Scale(flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f); transform.Translate(flipX ? this.width : 0.0f, flipY ? this.height : 0.0f); context.ConcatCTM(transform); this.image = context.ToImage(); } }
public BitmapSource RenderImageSource(ILUT lut) { var render = false; if (_bitmap == null) { _pixels = new PinnedIntArray(ScaledData.Width * ScaledData.Height); render = true; } if (_applyLut && lut != null && !lut.IsValid) { lut.Recalculate(); render = true; } if (render) { ScaledData.Render((_applyLut ? lut : null), _pixels.Data); foreach (var overlay in _overlays) { overlay.Render(_pixels.Data, ScaledData.Width, ScaledData.Height); } } using ( var context = new CGBitmapContext(_pixels, ScaledWidth, ScaledHeight, 8, 4 * ScaledWidth, CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedLast)) { var transform = CGAffineTransform.MakeRotation((float)(_rotation * Math.PI / 180.0)); transform.Scale(_flipX ? -1.0f : 1.0f, _flipY ? -1.0f : 1.0f); transform.Translate(_flipX ? ScaledWidth : 0.0f, _flipY ? ScaledHeight : 0.0f); context.ConcatCTM(transform); _bitmap = context.ToImage(); } return(_bitmap); }
private byte[] RotateImage(UIImage image) { UIImage imageToReturn = null; if (image.Size.Height > image.Size.Width) { imageToReturn = image; } else { CGAffineTransform transform = CGAffineTransform.MakeIdentity(); transform.Rotate(-(float)Math.PI / 2); transform.Translate(0, image.Size.Width); //now draw image using (var context = new CGBitmapContext(IntPtr.Zero, (int)image.Size.Height, (int)image.Size.Width, image.CGImage.BitsPerComponent, image.CGImage.BytesPerRow, image.CGImage.ColorSpace, image.CGImage.BitmapInfo)) { context.ConcatCTM(transform); context.DrawImage(new RectangleF(PointF.Empty, new SizeF((float)image.Size.Width, (float)image.Size.Height)), image.CGImage); using (var imageRef = context.ToImage()) { imageToReturn = new UIImage(imageRef); } } } using (NSData imageData = imageToReturn.AsPNG()) { Byte[] byteArray = new Byte[imageData.Length]; System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, byteArray, 0, Convert.ToInt32(imageData.Length)); return(byteArray); } }
public static XIR.Image RemoteRepresentation(this CGPath cgPath) { // We add just a little padding to keep from clipping the drawings that lie on the bounds. var width = (int)cgPath.PathBoundingBox.Width + 4 > 0 ? (int)cgPath.PathBoundingBox.Width + 4 : 200; var height = (int)cgPath.PathBoundingBox.Height + 4 > 0 ? (int)cgPath.PathBoundingBox.Height + 4 : 200; var bytesPerRow = width * 4; // We need to offset the image to keep from clipping the drawing. var offsetXZero = -cgPath.PathBoundingBox.X; var offsetYZero = -cgPath.PathBoundingBox.Y; // Create a transform to offset our drawing. var transform = CGAffineTransform.MakeIdentity(); transform.Translate(offsetXZero + 1, offsetYZero + 1); using (var context = new CGBitmapContext( IntPtr.Zero, width, height, 8, bytesPerRow, CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedFirst)) { // Make sure we offset our drawing to keep it form clipping context.ConcatCTM(transform); context.SaveState(); context.SetFillColor(brush.CGColor); context.AddPath(cgPath); context.FillPath(); context.RestoreState(); context.SetStrokeColor(pen.CGColor); context.SetLineWidth(1f); context.AddPath(cgPath); context.DrawPath(CGPathDrawingMode.Stroke); return(context.RemoteRepresentation()); } }
public static UIImage FixOrientation(this UIImage image) { if (image.Orientation == UIImageOrientation.Up) { return(image); } var transform = CGAffineTransform.MakeIdentity(); switch (image.Orientation) { case UIImageOrientation.Down: case UIImageOrientation.DownMirrored: transform = CGAffineTransform.Translate(transform, image.Size.Width, image.Size.Height); transform = CGAffineTransform.Rotate(transform, (float)Math.PI); break; case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: transform = CGAffineTransform.Translate(transform, image.Size.Width, 0); transform = CGAffineTransform.Rotate(transform, (float)Math.PI / 2); break; case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: transform = CGAffineTransform.Translate(transform, 0, image.Size.Height); transform = CGAffineTransform.Rotate(transform, -(float)Math.PI / 2); break; } switch (image.Orientation) { case UIImageOrientation.UpMirrored: case UIImageOrientation.DownMirrored: transform = CGAffineTransform.Translate(transform, image.Size.Width, 0); transform = CGAffineTransform.Scale(transform, -1, 1); break; case UIImageOrientation.LeftMirrored: case UIImageOrientation.RightMirrored: transform = CGAffineTransform.Translate(transform, image.Size.Height, 0); transform = CGAffineTransform.Scale(transform, -1, 1); break; } using (var cgImg = image.CGImage) using (var ctx = new CGBitmapContext(null, (nint)image.Size.Width, (nint)image.Size.Height, cgImg.BitsPerComponent, 0, cgImg.ColorSpace, cgImg.BitmapInfo)) { ctx.ConcatCTM(transform); switch (image.Orientation) { case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: ctx.DrawImage(new CGRect(0, 0, image.Size.Height, image.Size.Width), cgImg); break; default: ctx.DrawImage(new CGRect(0, 0, image.Size.Width, image.Size.Height), cgImg); break; } using (var newCgImg = ctx.ToImage()) { return(UIImage.FromImage(newCgImg)); } } }
public ESTexture2D(UIImage uiImage, All filter) { CGImage image = uiImage.CGImage; if (uiImage == null) { throw new ArgumentNullException("uiImage"); } // TODO: could use this to implement lower-bandwidth textures //bool hasAlpha = (image.AlphaInfo == CGImageAlphaInfo.First || image.AlphaInfo == CGImageAlphaInfo.Last // || image.AlphaInfo == CGImageAlphaInfo.PremultipliedFirst || image.AlphaInfo == CGImageAlphaInfo.PremultipliedLast); // Image dimentions: logicalSize = new Point((int)uiImage.Size.Width, (int)uiImage.Size.Height); pixelWidth = uiImage.CGImage.Width; pixelHeight = uiImage.CGImage.Height; // Round up the target texture width and height to powers of two: potWidth = pixelWidth; potHeight = pixelHeight; if ((potWidth & (potWidth - 1)) != 0) { int w = 1; while (w < potWidth) { w *= 2; } potWidth = w; } if ((potHeight & (potHeight - 1)) != 0) { int h = 1; while (h < potHeight) { h *= 2; } potHeight = h; } // Scale down textures that are too large... CGAffineTransform transform = CGAffineTransform.MakeIdentity(); while ((potWidth > 1024) || (potHeight > 1024)) { potWidth /= 2; // Note: no precision loss - it's a power of two potHeight /= 2; pixelWidth /= 2; // Note: precision loss - assume possibility of dropping a pixel at each step is ok pixelHeight /= 2; transform.Multiply(CGAffineTransform.MakeScale(0.5f, 0.5f)); } RecalculateRatio(); lock (textureLoadBufferLockObject) { CreateTextureLoadBuffer(); unsafe { fixed(byte *data = textureLoadBuffer) { var colorSpace = CGColorSpace.CreateDeviceRGB(); var context = new CGBitmapContext(new IntPtr(data), potWidth, potHeight, 8, 4 * potWidth, colorSpace, CGImageAlphaInfo.PremultipliedLast); context.ClearRect(new RectangleF(0, 0, potWidth, potHeight)); context.TranslateCTM(0, potHeight - pixelHeight); // TODO: this does not play nice with the precision-loss above (keeping half-pixel to the edge) if (!transform.IsIdentity) { context.ConcatCTM(transform); } context.DrawImage(new RectangleF(0, 0, image.Width, image.Height), image); SetupTexture(new IntPtr(data), filter); context.Dispose(); colorSpace.Dispose(); } } } }
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; }
public void GetData <T>(T[] data) { // TODO Causese AV on Device, but not simulator GetData<T>(0, null, data, 0, Width * Height); if (data == null) { throw new ArgumentException("data cannot be null"); } int sz = 0; byte[] pixel = new byte[4]; int pos; IntPtr pixelOffset; // Get the Color values if ((typeof(T) == typeof(Color))) { // Load up texture into memory UIImage uiImage = UIImage.FromBundle(this.Name); if (uiImage == null) { throw new ContentLoadException("Error loading file via UIImage: " + Name); } CGImage image = uiImage.CGImage; if (image == null) { throw new ContentLoadException("Error with CGIamge: " + Name); } int width, height, i; CGContext context = null; IntPtr imageData; CGColorSpace colorSpace; IntPtr tempData; bool hasAlpha; CGImageAlphaInfo info; CGAffineTransform transform; Size imageSize; SurfaceFormat pixelFormat; bool sizeToFit = false; info = image.AlphaInfo; hasAlpha = ((info == CGImageAlphaInfo.PremultipliedLast) || (info == CGImageAlphaInfo.PremultipliedFirst) || (info == CGImageAlphaInfo.Last) || (info == CGImageAlphaInfo.First) ? true : false); if (image.ColorSpace != null) { if (hasAlpha) { pixelFormat = SurfaceFormat.Rgba32; } else { pixelFormat = SurfaceFormat.Rgb32; } } else { pixelFormat = SurfaceFormat.Alpha8; } imageSize = new Size(image.Width, image.Height); transform = CGAffineTransform.MakeIdentity(); width = imageSize.Width; if ((width != 1) && ((width & (width - 1)) != 0)) { i = 1; while ((sizeToFit ? 2 * i : i) < width) { i *= 2; } width = i; } height = imageSize.Height; if ((height != 1) && ((height & (height - 1)) != 0)) { i = 1; while ((sizeToFit ? 2 * i : i) < height) { i *= 2; } height = i; } // TODO: kMaxTextureSize = 1024 while ((width > 1024) || (height > 1024)) { width /= 2; height /= 2; transform = CGAffineTransform.MakeScale(0.5f, 0.5f); imageSize.Width /= 2; imageSize.Height /= 2; } switch (pixelFormat) { case SurfaceFormat.Rgba32: colorSpace = CGColorSpace.CreateDeviceRGB(); imageData = Marshal.AllocHGlobal(height * width * 4); context = new CGBitmapContext(imageData, width, height, 8, 4 * width, colorSpace, CGImageAlphaInfo.PremultipliedLast); colorSpace.Dispose(); break; case SurfaceFormat.Rgb32: colorSpace = CGColorSpace.CreateDeviceRGB(); imageData = Marshal.AllocHGlobal(height * width * 4); context = new CGBitmapContext(imageData, width, height, 8, 4 * width, colorSpace, CGImageAlphaInfo.NoneSkipLast); colorSpace.Dispose(); break; case SurfaceFormat.Alpha8: imageData = Marshal.AllocHGlobal(height * width); context = new CGBitmapContext(imageData, width, height, 8, width, null, CGImageAlphaInfo.Only); break; default: throw new NotSupportedException("Invalid pixel format"); } context.ClearRect(new RectangleF(0, 0, width, height)); context.TranslateCTM(0, height - imageSize.Height); if (!transform.IsIdentity) { context.ConcatCTM(transform); } context.DrawImage(new RectangleF(0, 0, image.Width, image.Height), image); //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" if (pixelFormat == SurfaceFormat.Rgb32) { tempData = Marshal.AllocHGlobal(height * width * 2); int d32; short d16; int inPixel32Count = 0, outPixel16Count = 0; for (i = 0; i < width * height; ++i, inPixel32Count += sizeof(int)) { d32 = Marshal.ReadInt32(imageData, inPixel32Count); short R = (short)((((d32 >> 0) & 0xFF) >> 3) << 11); short G = (short)((((d32 >> 8) & 0xFF) >> 2) << 5); short B = (short)((((d32 >> 16) & 0xFF) >> 3) << 0); d16 = (short)(R | G | B); Marshal.WriteInt16(tempData, outPixel16Count, d16); outPixel16Count += sizeof(short); } Marshal.FreeHGlobal(imageData); imageData = tempData; } // Loop through and extract the data for (int y = 0; y < imageSize.Height; y++) { for (int x = 0; x < imageSize.Width; x++) { var result = new Color(0, 0, 0, 0); switch (pixelFormat) { case SurfaceFormat.Rgba32: //kTexture2DPixelFormat_RGBA8888 case SurfaceFormat.Dxt3: sz = 4; pos = ((y * imageSize.Width) + x) * sz; pixelOffset = new IntPtr(imageData.ToInt64() + pos); Marshal.Copy(pixelOffset, pixel, 0, 4); result.R = pixel[0]; result.G = pixel[1]; result.B = pixel[2]; result.A = pixel[3]; break; case SurfaceFormat.Bgra4444: //kTexture2DPixelFormat_RGBA4444 sz = 2; pos = ((y * imageSize.Width) + x) * sz; pixelOffset = new IntPtr(imageData.ToInt64() + pos); Marshal.Copy(pixelOffset, pixel, 0, 4); result.R = pixel[0]; result.G = pixel[1]; result.B = pixel[2]; result.A = pixel[3]; break; case SurfaceFormat.Bgra5551: //kTexture2DPixelFormat_RGB5A1 sz = 2; pos = ((y * imageSize.Width) + x) * sz; pixelOffset = new IntPtr(imageData.ToInt64() + pos); Marshal.Copy(pixelOffset, pixel, 0, 4); result.R = pixel[0]; result.G = pixel[1]; result.B = pixel[2]; result.A = pixel[3]; break; case SurfaceFormat.Rgb32: // kTexture2DPixelFormat_RGB565 sz = 2; pos = ((y * imageSize.Width) + x) * sz; pixelOffset = new IntPtr(imageData.ToInt64() + pos); Marshal.Copy(pixelOffset, pixel, 0, 4); result.R = pixel[0]; result.G = pixel[1]; result.B = pixel[2]; result.A = 255; break; case SurfaceFormat.Alpha8: // kTexture2DPixelFormat_A8 sz = 1; pos = ((y * imageSize.Width) + x) * sz; pixelOffset = new IntPtr(imageData.ToInt64() + pos); Marshal.Copy(pixelOffset, pixel, 0, 4); result.A = pixel[0]; break; default: throw new NotSupportedException("Texture format"); } data[((y * imageSize.Width) + x)] = (T)(object)result; } } context.Dispose(); Marshal.FreeHGlobal(imageData); } }
private void InitWithCGImage(CGImage image, All filter) { int width,height,i; CGContext context = null; IntPtr data; CGColorSpace colorSpace; IntPtr tempData; bool hasAlpha; CGImageAlphaInfo info; CGAffineTransform transform; Size imageSize; SurfaceFormat pixelFormat; bool sizeToFit = false; if(image == null) { throw new ArgumentException(" uimage is invalid! " ); } info = image.AlphaInfo; hasAlpha = ((info == CGImageAlphaInfo.PremultipliedLast) || (info == CGImageAlphaInfo.PremultipliedFirst) || (info == CGImageAlphaInfo.Last) || (info == CGImageAlphaInfo.First) ? true : false); if (image.ColorSpace != null) { pixelFormat = SurfaceFormat.Color; } else { pixelFormat = SurfaceFormat.Alpha8; } imageSize = new Size(image.Width,image.Height); transform = CGAffineTransform.MakeIdentity(); width = imageSize.Width; if((width != 1) && ((width & (width - 1))!=0)) { i = 1; while((sizeToFit ? 2 * i : i) < width) i *= 2; width = i; } height = imageSize.Height; if((height != 1) && ((height & (height - 1))!=0)) { i = 1; while((sizeToFit ? 2 * i : i) < height) i *= 2; height = i; } // TODO: kMaxTextureSize = 1024 while((width > 1024) || (height > 1024)) { width /= 2; height /= 2; transform = CGAffineTransform.MakeScale(0.5f,0.5f); imageSize.Width /= 2; imageSize.Height /= 2; } switch(pixelFormat) { case SurfaceFormat.Color: colorSpace = CGColorSpace.CreateDeviceRGB(); data = Marshal.AllocHGlobal(height * width * 4); context = new CGBitmapContext(data, width, height, 8, 4 * width, colorSpace,CGImageAlphaInfo.PremultipliedLast); colorSpace.Dispose(); break; case SurfaceFormat.Alpha8: data = Marshal.AllocHGlobal(height * width); context = new CGBitmapContext(data, width, height, 8, width, null, CGImageAlphaInfo.Only); break; default: throw new NotSupportedException("Invalid pixel format"); } context.ClearRect(new RectangleF(0,0,width,height)); context.TranslateCTM(0, height - imageSize.Height); if (!transform.IsIdentity) { context.ConcatCTM(transform); } context.DrawImage(new RectangleF(0, 0, image.Width, image.Height), image); //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" /* if(pixelFormat == SurfaceFormat.Rgb32) { tempData = Marshal.AllocHGlobal(height * width * 2); int d32; short d16; int inPixel32Count=0,outPixel16Count=0; for(i = 0; i < width * height; ++i, inPixel32Count+=sizeof(int)) { d32 = Marshal.ReadInt32(data,inPixel32Count); short R = (short)((((d32 >> 0) & 0xFF) >> 3) << 11); short G = (short)((((d32 >> 8) & 0xFF) >> 2) << 5); short B = (short)((((d32 >> 16) & 0xFF) >> 3) << 0); d16 = (short) (R | G | B); Marshal.WriteInt16(tempData,outPixel16Count,d16); outPixel16Count += sizeof(short); } Marshal.FreeHGlobal(data); data = tempData; } */ InitWithData(data,pixelFormat,width,height,imageSize, filter); context.Dispose(); Marshal.FreeHGlobal (data); }
private void InitWithCGImage(CGImage image) { int width, height; CGBitmapContext bitmap = null; bool hasAlpha; CGImageAlphaInfo alphaInfo; CGColorSpace colorSpace; int bitsPerComponent, bytesPerRow; CGBitmapFlags bitmapInfo; bool premultiplied = false; int bitsPerPixel = 0; if (image == null) { throw new ArgumentException(" image is invalid! "); } alphaInfo = image.AlphaInfo; hasAlpha = ((alphaInfo == CGImageAlphaInfo.PremultipliedLast) || (alphaInfo == CGImageAlphaInfo.PremultipliedFirst) || (alphaInfo == CGImageAlphaInfo.Last) || (alphaInfo == CGImageAlphaInfo.First) ? true : false); imageSize.Width = image.Width; imageSize.Height = image.Height; width = image.Width; height = image.Height; // Not sure yet if we need to keep the original image information // before we change it internally. TODO look at what windows does // and follow that. bitmapInfo = image.BitmapInfo; bitsPerComponent = image.BitsPerComponent; bitsPerPixel = image.BitsPerPixel; bytesPerRow = width * bitsPerPixel / bitsPerComponent; int size = bytesPerRow * height; colorSpace = image.ColorSpace; // Right now internally we represent the images all the same // I left the call here just in case we find that this is not // possible. Read the comments for non alpha images. if (colorSpace != null) { if (hasAlpha) { premultiplied = true; colorSpace = CGColorSpace.CreateDeviceRGB(); bitsPerComponent = 8; bitsPerPixel = 32; bitmapInfo = CGBitmapFlags.PremultipliedLast; } else { // even for images without alpha we will internally // represent them as RGB with alpha. There were problems // if we do not do it this way and creating a bitmap context. // The images were not drawing correctly and tearing. Also // creating a Graphics to draw on was a nightmare. This // should probably be looked into or maybe it is ok and we // can continue representing internally with this representation premultiplied = true; colorSpace = CGColorSpace.CreateDeviceRGB(); bitsPerComponent = 8; bitsPerPixel = 32; bitmapInfo = CGBitmapFlags.PremultipliedLast; } } else { premultiplied = true; colorSpace = CGColorSpace.CreateDeviceRGB(); bitsPerComponent = 8; bitsPerPixel = 32; bitmapInfo = CGBitmapFlags.PremultipliedLast; } bytesPerRow = width * bitsPerPixel / bitsPerComponent; size = bytesPerRow * height; bitmapBlock = Marshal.AllocHGlobal(size); bitmap = new CGBitmapContext(bitmapBlock, image.Width, image.Width, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo); bitmap.ClearRect(new RectangleF(0, 0, width, height)); // We need to flip the Y axis to go from right handed to lefted handed coordinate system var transform = new CGAffineTransform(1, 0, 0, -1, 0, image.Height); bitmap.ConcatCTM(transform); bitmap.DrawImage(new RectangleF(0, 0, image.Width, image.Height), image); var provider = new CGDataProvider(bitmapBlock, size, true); NativeCGImage = new CGImage(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpace, bitmapInfo, provider, null, false, CGColorRenderingIntent.Default); colorSpace.Dispose(); bitmap.Dispose(); }
UIImage FixOrientation(UIImage image) { if (image.Orientation == UIImageOrientation.Up) return image; CGAffineTransform transform = CGAffineTransform.MakeIdentity (); switch (image.Orientation) { case UIImageOrientation.Down: case UIImageOrientation.DownMirrored: transform = CGAffineTransform.Translate (transform, image.Size.Width, image.Size.Height); transform = CGAffineTransform.Rotate (transform, (nfloat)(Math.PI)); break; case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: transform = CGAffineTransform.Translate (transform, image.Size.Width, 0); transform = CGAffineTransform.Rotate (transform, (nfloat)(Math.PI / 2)); break; case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: transform = CGAffineTransform.Translate (transform, 0, image.Size.Height); transform = CGAffineTransform.Rotate (transform, (nfloat)(-1 * Math.PI / 2)); break; case UIImageOrientation.Up: case UIImageOrientation.UpMirrored: break; } switch (image.Orientation) { case UIImageOrientation.UpMirrored: case UIImageOrientation.DownMirrored: transform = CGAffineTransform.Translate (transform, image.Size.Width, 0); transform = CGAffineTransform.Scale (transform, -1, 1); break; case UIImageOrientation.LeftMirrored: case UIImageOrientation.RightMirrored: transform = CGAffineTransform.Translate (transform, image.Size.Height, 0); transform = CGAffineTransform.Scale (transform, -1, 1); break; case UIImageOrientation.Up: case UIImageOrientation.Down: case UIImageOrientation.Left: case UIImageOrientation.Right: break; } using (CGBitmapContext ctx = new CGBitmapContext (null, (nint)image.Size.Width, (nint)image.Size.Height, (nint)image.CGImage.BitsPerComponent, (nint)0, image.CGImage.ColorSpace, image.CGImage.BitmapInfo)) { ctx.ConcatCTM (transform); switch (image.Orientation) { case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: ctx.DrawImage (new CGRect (0, 0, image.Size.Height, image.Size.Width), image.CGImage); break; default: ctx.DrawImage (new CGRect (0, 0, image.Size.Width, image.Size.Height), image.CGImage); break; } using (var cgImage = ctx.ToImage ()) { return new UIImage (cgImage); } } }
public static UIImage FixOrientation(UIImage originalImage) { if (originalImage.Orientation == UIImageOrientation.Up) { return(originalImage); } CGAffineTransform transform = CGAffineTransform.MakeIdentity(); switch (originalImage.Orientation) { case UIImageOrientation.Down: case UIImageOrientation.DownMirrored: transform.Rotate((float)Math.PI); transform.Translate(originalImage.Size.Width, originalImage.Size.Height); break; case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: transform.Rotate((float)Math.PI / 2); transform.Translate(originalImage.Size.Width, 0); break; case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: transform.Rotate(-(float)Math.PI / 2); transform.Translate(0, originalImage.Size.Height); break; case UIImageOrientation.Up: case UIImageOrientation.UpMirrored: break; } switch (originalImage.Orientation) { case UIImageOrientation.UpMirrored: case UIImageOrientation.DownMirrored: transform.Translate(originalImage.Size.Width, 0); transform.Scale(-1, 1); break; case UIImageOrientation.LeftMirrored: case UIImageOrientation.RightMirrored: transform.Translate(originalImage.Size.Height, 0); transform.Scale(-1, 1); break; case UIImageOrientation.Up: case UIImageOrientation.Down: case UIImageOrientation.Left: case UIImageOrientation.Right: break; } var ctx = new CGBitmapContext(IntPtr.Zero, (nint)originalImage.Size.Width, (nint)originalImage.Size.Height, originalImage.CGImage.BitsPerComponent, originalImage.CGImage.BytesPerRow, originalImage.CGImage.ColorSpace, originalImage.CGImage.BitmapInfo); ctx.ConcatCTM(transform); switch (originalImage.Orientation) { case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: ctx.DrawImage(new CGRect(0, 0, originalImage.Size.Height, originalImage.Size.Width), originalImage.CGImage); break; default: ctx.DrawImage(new CGRect(0, 0, originalImage.Size.Width, originalImage.Size.Height), originalImage.CGImage); break; } var cgImage = ctx.ToImage(); UIImage result = UIImage.FromImage(cgImage); ctx.Dispose(); cgImage.Dispose(); return(result); }
/// <summary> /// Returns thumb image object for page /// </summary> /// <param name="thumbContentSize">Thumb content size</param> /// <param name="pageNumber">Page number for what will created image object</param> /// <returns>Page image object</returns> private static UIImage GetThumbImage(float thumbContentSize, int pageNumber) { if ((pageNumber <= 0) || (pageNumber > PDFDocument.PageCount)) { return null; } // Calc page view size var pageSize = PageContentView.GetPageViewSize(pageNumber); if (pageSize.Width % 2 > 0) { pageSize.Width--; } if (pageSize.Height % 2 > 0) { pageSize.Height--; } // Calc target size var targetSize = new Size((int)pageSize.Width, (int)pageSize.Height); // Draw page on CGImage CGImage pageImage; using (CGColorSpace rgb = CGColorSpace.CreateDeviceRGB()) { using (var context = new CGBitmapContext(null, targetSize.Width, targetSize.Height, 8, 0, rgb, CGBitmapFlags.ByteOrder32Little | CGBitmapFlags.NoneSkipFirst)) { using (var pdfPage = PDFDocument.GetPage(pageNumber)) { // Draw page on custom CGBitmap context var thumbRect = new RectangleF(0.0f, 0.0f, targetSize.Width, targetSize.Height); context.SetFillColor(1.0f, 1.0f, 1.0f, 1.0f); context.FillRect(thumbRect); context.ConcatCTM(pdfPage.GetDrawingTransform(CGPDFBox.Crop, thumbRect, 0, true)); context.SetRenderingIntent(CGColorRenderingIntent.Default); context.InterpolationQuality = CGInterpolationQuality.Default; context.DrawPDFPage(pdfPage); // Create CGImage from custom CGBitmap context pageImage = context.ToImage(); } } } return UIImage.FromImage(pageImage); }
public Texture2D(UIImage uiImage) { if (uiImage == null) { throw new ArgumentNullException("uiImage"); } CGImage image = uiImage.CGImage; if (image == null) { throw new InvalidOperationException("Attempted to create a Texture2D from UIImage, but resulting CGImage is null"); } CGImageAlphaInfo info = image.AlphaInfo; bool hasAlpha = info == CGImageAlphaInfo.PremultipliedLast || info == CGImageAlphaInfo.PremultipliedFirst || info == CGImageAlphaInfo.Last || info == CGImageAlphaInfo.First; int bpp = image.BitsPerComponent; Texture2DPixelFormat pixelFormat; if (image.ColorSpace != null) { if (hasAlpha || bpp >= 8) { pixelFormat = Texture2DPixelFormat.Default; } else { pixelFormat = Texture2DPixelFormat.RGB565; } } else { pixelFormat = Texture2DPixelFormat.A8; } int width = image.Width; if (width != 1 && (width & (width - 1)) != 0) { int i = 1; while (i < width) { i *= 2; } width = i; } int height = image.Height; if (height != 1 && (height & (height - 1)) != 0) { int i = 1; while (i < height) { i *= 2; } height = i; } if (width > MaxTextureSize || height > MaxTextureSize) { throw new InvalidOperationException("Image is too large. Width or height larger than MaxTextureSize"); } CGColorSpace colorSpace = null; CGContext context; byte[] data; unsafe { // all formats require w*h*4, except A8 requires just w*h int dataSize = width * height * 4; if (pixelFormat == Texture2DPixelFormat.A8) { dataSize = width * height; } data = new byte[dataSize]; fixed (byte* dp = data) { switch (pixelFormat) { case Texture2DPixelFormat.RGBA8888: case Texture2DPixelFormat.RGBA4444: case Texture2DPixelFormat.RGB5A1: colorSpace = CGColorSpace.CreateDeviceRGB(); context = new CGBitmapContext((IntPtr)dp, (int)width, (int)height, 8, 4 * (int)width, colorSpace, CGImageAlphaInfo.PremultipliedLast); break; case Texture2DPixelFormat.RGB565: colorSpace = CGColorSpace.CreateDeviceRGB(); context = new CGBitmapContext((IntPtr)dp, (int)width, (int)height, 8, 4 * (int)width, colorSpace, CGImageAlphaInfo.NoneSkipLast); break; case Texture2DPixelFormat.A8: context = new CGBitmapContext((IntPtr)dp, (int)width, (int)height, 8, (int)width, null, CGImageAlphaInfo.Only); break; default: throw new InvalidEnumArgumentException("pixelFormat", (int)pixelFormat, typeof(Texture2DPixelFormat)); } if (colorSpace != null) { colorSpace.Dispose(); } context.ClearRect(new RectangleF(0, 0, width, height)); context.TranslateCTM(0, height - image.Height); // why is this here? make an identity transform, then immediately not use it? Need to look into this CGAffineTransform transform = CGAffineTransform.MakeIdentity(); if (!transform.IsIdentity) { context.ConcatCTM(transform); } context.DrawImage(new RectangleF(0, 0, image.Width, image.Height), image); } } if (pixelFormat == Texture2DPixelFormat.RGB565) { //Convert "RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" byte[] tempData = new byte[height * width * 2]; unsafe { fixed (byte* inPixel32b = data) { uint* inPixel32 = (uint*)inPixel32b; fixed (byte* outPixel16b = tempData) { ushort* outPixel16 = (ushort*)outPixel16b; for (int i = 0; i < width * height; ++i,++inPixel32) { uint tempInt32 = ((((*inPixel32 >> 0) & 0xff) >> 3) << 11) | ((((*inPixel32 >> 8) & 0xff) >> 2) << 5) | ((((*inPixel32 >> 16) & 0xff) >> 3) << 0); *outPixel16++ = (ushort)tempInt32; } } } } data = tempData; } else if (pixelFormat == Texture2DPixelFormat.RGBA4444) { //Convert "RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA" byte[] tempData = new byte[height * width * 2]; unsafe { fixed (byte* inPixel32b = data) { uint* inPixel32 = (uint*)inPixel32b; fixed (byte* outPixel16b = tempData) { ushort* outPixel16 = (ushort*)outPixel16b; for (int i = 0; i < width * height; ++i,++inPixel32) { uint tempInt32 = ((((*inPixel32 >> 0) & 0xff) >> 4) << 12) | ((((*inPixel32 >> 8) & 0xff) >> 4) << 8) | ((((*inPixel32 >> 16) & 0xff) >> 4) << 4) | ((((*inPixel32 >> 24) & 0xff) >> 4) << 0); *outPixel16++ = (ushort)tempInt32; } } } } data = tempData; } else if (pixelFormat == Texture2DPixelFormat.RGB5A1) { //Convert "RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGBBBBBA" byte[] tempData = new byte[height * width * 2]; unsafe { fixed (byte* inPixel32b = data) { uint* inPixel32 = (uint*)inPixel32b; fixed (byte* outPixel16b = tempData) { ushort* outPixel16 = (ushort*)outPixel16b; for (int i = 0; i < width * height; ++i,++inPixel32) { uint tempInt32 = ((((*inPixel32 >> 0) & 0xff) >> 3) << 11) | ((((*inPixel32 >> 8) & 0xff) >> 3) << 6) | ((((*inPixel32 >> 16) & 0xff) >> 3) << 1) | ((((*inPixel32 >> 24) & 0xff) >> 7) << 0); *outPixel16++ = (ushort)tempInt32; } } } } data = tempData; } InitWithData(data, pixelFormat, width, height, new SizeF(image.Width, image.Height)); HasPremultipliedAlpha = info == CGImageAlphaInfo.PremultipliedLast || info == CGImageAlphaInfo.PremultipliedFirst; context.Dispose(); }
private void InitWithCGImage(CGImage image) { int width, height; CGBitmapContext bitmap = null; bool hasAlpha; CGImageAlphaInfo alphaInfo; CGColorSpace colorSpace; int bitsPerComponent, bytesPerRow; CGBitmapFlags bitmapInfo; bool premultiplied = false; int bitsPerPixel = 0; if (image == null) { throw new ArgumentException (" image is invalid! " ); } alphaInfo = image.AlphaInfo; hasAlpha = ((alphaInfo == CGImageAlphaInfo.PremultipliedLast) || (alphaInfo == CGImageAlphaInfo.PremultipliedFirst) || (alphaInfo == CGImageAlphaInfo.Last) || (alphaInfo == CGImageAlphaInfo.First) ? true : false); imageSize.Width = (int)image.Width; imageSize.Height = (int)image.Height; width = (int)image.Width; height = (int)image.Height; // Not sure yet if we need to keep the original image information // before we change it internally. TODO look at what windows does // and follow that. bitmapInfo = image.BitmapInfo; bitsPerComponent = (int)image.BitsPerComponent; bitsPerPixel = (int)image.BitsPerPixel; bytesPerRow = width * bitsPerPixel/bitsPerComponent; int size = bytesPerRow * height; colorSpace = image.ColorSpace; // Right now internally we represent the images all the same // I left the call here just in case we find that this is not // possible. Read the comments for non alpha images. if(colorSpace != null) { if( hasAlpha ) { premultiplied = true; colorSpace = CGColorSpace.CreateDeviceRGB (); bitsPerComponent = 8; bitsPerPixel = 32; bitmapInfo = CGBitmapFlags.PremultipliedLast; } else { // even for images without alpha we will internally // represent them as RGB with alpha. There were problems // if we do not do it this way and creating a bitmap context. // The images were not drawing correctly and tearing. Also // creating a Graphics to draw on was a nightmare. This // should probably be looked into or maybe it is ok and we // can continue representing internally with this representation premultiplied = true; colorSpace = CGColorSpace.CreateDeviceRGB (); bitsPerComponent = 8; bitsPerPixel = 32; bitmapInfo = CGBitmapFlags.NoneSkipLast; } } else { premultiplied = true; colorSpace = CGColorSpace.CreateDeviceRGB (); bitsPerComponent = 8; bitsPerPixel = 32; bitmapInfo = CGBitmapFlags.NoneSkipLast; } bytesPerRow = width * bitsPerPixel/bitsPerComponent; size = bytesPerRow * height; bitmapBlock = Marshal.AllocHGlobal (size); bitmap = new CGBitmapContext (bitmapBlock, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo); bitmap.ClearRect (new CGRect (0,0,width,height)); // We need to flip the Y axis to go from right handed to lefted handed coordinate system var transform = new CGAffineTransform(1, 0, 0, -1, 0, image.Height); bitmap.ConcatCTM(transform); bitmap.DrawImage (new CGRect (0, 0, image.Width, image.Height), image); var provider = new CGDataProvider (bitmapBlock, size, true); NativeCGImage = new CGImage (width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpace, bitmapInfo, provider, null, true, image.RenderingIntent); colorSpace.Dispose(); bitmap.Dispose(); }
//Create a Method to set orientation of image... private byte[] RotateImage(UIImage image) { UIImage imageToReturn = null; if (image.Orientation == UIImageOrientation.Up) { imageToReturn = image; } else { CGAffineTransform transform = CGAffineTransform.MakeIdentity(); switch (image.Orientation) { case UIImageOrientation.Down: case UIImageOrientation.DownMirrored: transform.Rotate((float)Math.PI); transform.Translate(image.Size.Width, image.Size.Height); break; case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: transform.Rotate((float)Math.PI / 2); transform.Translate(image.Size.Width, 0); break; case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: transform.Rotate(-(float)Math.PI / 2); transform.Translate(0, image.Size.Height); break; case UIImageOrientation.Up: case UIImageOrientation.UpMirrored: break; } switch (image.Orientation) { case UIImageOrientation.UpMirrored: case UIImageOrientation.DownMirrored: transform.Translate(image.Size.Width, 0); transform.Scale(-1, 1); break; case UIImageOrientation.LeftMirrored: case UIImageOrientation.RightMirrored: transform.Translate(image.Size.Height, 0); transform.Scale(-1, 1); break; case UIImageOrientation.Up: case UIImageOrientation.Down: case UIImageOrientation.Left: case UIImageOrientation.Right: break; } //now draw image using (var context = new CGBitmapContext(IntPtr.Zero, (int)image.Size.Width, (int)image.Size.Height, image.CGImage.BitsPerComponent, image.CGImage.BytesPerRow, image.CGImage.ColorSpace, image.CGImage.BitmapInfo)) { context.ConcatCTM(transform); switch (image.Orientation) { case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: // Grr... context.DrawImage(new RectangleF(PointF.Empty, new SizeF((float)image.Size.Height, (float)image.Size.Width)), image.CGImage); break; default: context.DrawImage(new RectangleF(PointF.Empty, new SizeF((float)image.Size.Width, (float)image.Size.Height)), image.CGImage); break; } using (var imageRef = context.ToImage()) { imageToReturn = new UIImage(imageRef); } } } using (NSData imageData = imageToReturn.AsJPEG()) { Byte[] byteArray = new Byte[imageData.Length]; System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, byteArray, 0, Convert.ToInt32(imageData.Length)); return(byteArray); } }
// Draws our animation path on the background image, just to show it protected void DrawPathAsBackground () { // create our offscreen bitmap context var bitmapSize = new SizeF (View.Frame.Size); using (var context = new CGBitmapContext ( IntPtr.Zero, (int)bitmapSize.Width, (int)bitmapSize.Height, 8, (int)(4 * bitmapSize.Width), CGColorSpace.CreateDeviceRGB (), CGImageAlphaInfo.PremultipliedFirst)) { // convert to View space var affineTransform = CGAffineTransform.MakeIdentity (); // invert the y axis affineTransform.Scale (1f, -1f); // move the y axis up affineTransform.Translate (0, View.Frame.Height); context.ConcatCTM (affineTransform); // actually draw the path context.AddPath (animationPath); context.SetStrokeColor (UIColor.LightGray.CGColor); context.SetLineWidth (3f); context.StrokePath (); // set what we've drawn as the backgound image backgroundImage.Image = UIImage.FromImage (context.ToImage()); } }
private void InitWithCGImage(CGImage image, All filter) { int width, height, i; CGContext context = null; IntPtr data; CGColorSpace colorSpace; IntPtr tempData; bool hasAlpha; CGImageAlphaInfo info; CGAffineTransform transform; Size imageSize; SurfaceFormat pixelFormat; bool sizeToFit = false; if (image == null) { throw new ArgumentException(" NSImage is invalid! "); } info = image.AlphaInfo; hasAlpha = ((info == CGImageAlphaInfo.PremultipliedLast) || (info == CGImageAlphaInfo.PremultipliedFirst) || (info == CGImageAlphaInfo.Last) || (info == CGImageAlphaInfo.First) ? true : false); if (image.ColorSpace != null) { if (hasAlpha) { pixelFormat = SurfaceFormat.Rgba32; } else { pixelFormat = SurfaceFormat.Rgb32; } } else { pixelFormat = SurfaceFormat.Alpha8; } imageSize = new Size(image.Width, image.Height); transform = CGAffineTransform.MakeIdentity(); width = imageSize.Width; if ((width != 1) && ((width & (width - 1)) != 0)) { i = 1; while ((sizeToFit ? 2 * i : i) < width) { i *= 2; } width = i; } height = imageSize.Height; if ((height != 1) && ((height & (height - 1)) != 0)) { i = 1; while ((sizeToFit ? 2 * i : i) < height) { i *= 2; } height = i; } // TODO: kMaxTextureSize = 1024 while ((width > 1024) || (height > 1024)) { width /= 2; height /= 2; transform = CGAffineTransform.MakeScale(0.5f, 0.5f); imageSize.Width /= 2; imageSize.Height /= 2; } switch (pixelFormat) { case SurfaceFormat.Rgba32: colorSpace = CGColorSpace.CreateDeviceRGB(); data = Marshal.AllocHGlobal(height * width * 4); context = new CGBitmapContext(data, width, height, 8, 4 * width, colorSpace, CGImageAlphaInfo.PremultipliedLast); colorSpace.Dispose(); break; case SurfaceFormat.Rgb32: colorSpace = CGColorSpace.CreateDeviceRGB(); data = Marshal.AllocHGlobal(height * width * 4); context = new CGBitmapContext(data, width, height, 8, 4 * width, colorSpace, CGImageAlphaInfo.NoneSkipLast); colorSpace.Dispose(); break; case SurfaceFormat.Alpha8: data = Marshal.AllocHGlobal(height * width); context = new CGBitmapContext(data, width, height, 8, width, null, CGImageAlphaInfo.Only); break; default: throw new NotSupportedException("Invalid pixel format"); } context.ClearRect(new RectangleF(0, 0, width, height)); context.TranslateCTM(0, height - imageSize.Height); if (!transform.IsIdentity) { context.ConcatCTM(transform); } context.DrawImage(new RectangleF(0, 0, image.Width, image.Height), image); //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" if (pixelFormat == SurfaceFormat.Rgb32) { tempData = Marshal.AllocHGlobal(height * width * 2); int d32; short d16; int inPixel32Count = 0, outPixel16Count = 0; for (i = 0; i < width * height; ++i, inPixel32Count += sizeof(int)) { d32 = Marshal.ReadInt32(data, inPixel32Count); short R = (short)((((d32 >> 0) & 0xFF) >> 3) << 11); short G = (short)((((d32 >> 8) & 0xFF) >> 2) << 5); short B = (short)((((d32 >> 16) & 0xFF) >> 3) << 0); d16 = (short)(R | G | B); Marshal.WriteInt16(tempData, outPixel16Count, d16); outPixel16Count += sizeof(short); } Marshal.FreeHGlobal(data); data = tempData; } InitWithData(data, pixelFormat, width, height, imageSize, filter); context.Dispose(); Marshal.FreeHGlobal(data); }
public static Stream RotateImage(UIImage image, int compressionQuality, string pathExtension) { UIImage imageToReturn = null; if (image.Orientation == UIImageOrientation.Up) { imageToReturn = image; } else { var transform = CGAffineTransform.MakeIdentity(); switch (image.Orientation) { case UIImageOrientation.Down: case UIImageOrientation.DownMirrored: transform.Rotate((float)Math.PI); transform.Translate(image.Size.Width, image.Size.Height); break; case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: transform.Rotate((float)Math.PI / 2); transform.Translate(image.Size.Width, 0); break; case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: transform.Rotate(-(float)Math.PI / 2); transform.Translate(0, image.Size.Height); break; case UIImageOrientation.Up: case UIImageOrientation.UpMirrored: break; } switch (image.Orientation) { case UIImageOrientation.UpMirrored: case UIImageOrientation.DownMirrored: transform.Translate(image.Size.Width, 0); transform.Scale(-1, 1); break; case UIImageOrientation.LeftMirrored: case UIImageOrientation.RightMirrored: transform.Translate(image.Size.Height, 0); transform.Scale(-1, 1); break; case UIImageOrientation.Up: case UIImageOrientation.Down: case UIImageOrientation.Left: case UIImageOrientation.Right: break; } using var context = new CGBitmapContext(IntPtr.Zero, (int)image.Size.Width, (int)image.Size.Height, image.CGImage.BitsPerComponent, image.CGImage.BytesPerRow, image.CGImage.ColorSpace, image.CGImage.BitmapInfo); context.ConcatCTM(transform); switch (image.Orientation) { case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: context.DrawImage(new CGRect(0, 0, image.Size.Height, image.Size.Width), image.CGImage); break; default: context.DrawImage(new CGRect(0, 0, image.Size.Width, image.Size.Height), image.CGImage); break; } using var imageRef = context.ToImage(); imageToReturn = new UIImage(imageRef, 1, UIImageOrientation.Up); } pathExtension = pathExtension.ToLowerInvariant(); var finalQuality = pathExtension == "jpg" ? (compressionQuality / 100f) : 0f; var imageData = pathExtension == "jpg" ? imageToReturn.AsJPEG(finalQuality) : imageToReturn.AsPNG(); //continue to move down quality , rare instances while (imageData == null && finalQuality > 0) { finalQuality -= 0.05f; imageData = imageToReturn.AsJPEG(finalQuality); } if (imageData == null) { throw new NullReferenceException("Unable to convert image to jpeg, please ensure file exists or lower quality level"); } var stream = new MemoryStream(); imageData.AsStream().CopyTo(stream); stream.Position = 0; imageData.Dispose(); image.Dispose(); image = null; return(stream); }
public ESTexture2D(UIImage uiImage, All filter) { CGImage image = uiImage.CGImage; if(uiImage == null) throw new ArgumentNullException("uiImage"); // TODO: could use this to implement lower-bandwidth textures //bool hasAlpha = (image.AlphaInfo == CGImageAlphaInfo.First || image.AlphaInfo == CGImageAlphaInfo.Last // || image.AlphaInfo == CGImageAlphaInfo.PremultipliedFirst || image.AlphaInfo == CGImageAlphaInfo.PremultipliedLast); // Image dimentions: logicalSize = new Point((int)uiImage.Size.Width, (int)uiImage.Size.Height); pixelWidth = uiImage.CGImage.Width; pixelHeight = uiImage.CGImage.Height; // Round up the target texture width and height to powers of two: potWidth = pixelWidth; potHeight = pixelHeight; if(( potWidth & ( potWidth-1)) != 0) { int w = 1; while(w < potWidth) { w *= 2; } potWidth = w; } if((potHeight & (potHeight-1)) != 0) { int h = 1; while(h < potHeight) { h *= 2; } potHeight = h; } // Scale down textures that are too large... CGAffineTransform transform = CGAffineTransform.MakeIdentity(); while((potWidth > 1024) || (potHeight > 1024)) { potWidth /= 2; // Note: no precision loss - it's a power of two potHeight /= 2; pixelWidth /= 2; // Note: precision loss - assume possibility of dropping a pixel at each step is ok pixelHeight /= 2; transform.Multiply(CGAffineTransform.MakeScale(0.5f, 0.5f)); } RecalculateRatio(); lock(textureLoadBufferLockObject) { CreateTextureLoadBuffer(); unsafe { fixed(byte* data = textureLoadBuffer) { var colorSpace = CGColorSpace.CreateDeviceRGB(); var context = new CGBitmapContext(new IntPtr(data), potWidth, potHeight, 8, 4 * potWidth, colorSpace, CGImageAlphaInfo.PremultipliedLast); context.ClearRect(new RectangleF(0, 0, potWidth, potHeight)); context.TranslateCTM(0, potHeight - pixelHeight); // TODO: this does not play nice with the precision-loss above (keeping half-pixel to the edge) if(!transform.IsIdentity) context.ConcatCTM(transform); context.DrawImage(new RectangleF(0, 0, image.Width, image.Height), image); SetupTexture(new IntPtr(data), filter); context.Dispose(); colorSpace.Dispose(); } } } }
static Texture2D FromUIImage(UIImage uiImage, string name) { All filter = All.Linear; CGImage image = uiImage.CGImage; if(uiImage == null) throw new ArgumentNullException("uiImage"); // TODO: could use this to implement lower-bandwidth textures //bool hasAlpha = (image.AlphaInfo == CGImageAlphaInfo.First || image.AlphaInfo == CGImageAlphaInfo.Last // || image.AlphaInfo == CGImageAlphaInfo.PremultipliedFirst || image.AlphaInfo == CGImageAlphaInfo.PremultipliedLast); // Image dimentions: Point logicalSize = new Point((int)uiImage.Size.Width, (int)uiImage.Size.Height); int pixelWidth = uiImage.CGImage.Width; int pixelHeight = uiImage.CGImage.Height; // Round up the target texture width and height to powers of two: int potWidth = pixelWidth; int potHeight = pixelHeight; if(( potWidth & ( potWidth-1)) != 0) { int w = 1; while(w < potWidth) { w *= 2; } potWidth = w; } if((potHeight & (potHeight-1)) != 0) { int h = 1; while(h < potHeight) { h *= 2; } potHeight = h; } // Scale down textures that are too large... CGAffineTransform transform = CGAffineTransform.MakeIdentity(); while((potWidth > 1024) || (potHeight > 1024)) { potWidth /= 2; // Note: no precision loss - it's a power of two potHeight /= 2; pixelWidth /= 2; // Note: precision loss - assume possibility of dropping a pixel at each step is ok pixelHeight /= 2; transform.Multiply(CGAffineTransform.MakeScale(0.5f, 0.5f)); } lock(textureLoadBufferLockObject) { CreateTextureLoadBuffer(); unsafe { fixed(byte* data = textureLoadBuffer) { using(var colorSpace = CGColorSpace.CreateDeviceRGB()) using(var context = new CGBitmapContext(new IntPtr(data), potWidth, potHeight, 8, 4 * potWidth, colorSpace, CGImageAlphaInfo.PremultipliedLast)) { context.ClearRect(new RectangleF(0, 0, potWidth, potHeight)); context.TranslateCTM(0, potHeight - pixelHeight); // TODO: this does not play nice with the precision-loss above (keeping half-pixel to the edge) if(!transform.IsIdentity) context.ConcatCTM(transform); context.DrawImage(new RectangleF(0, 0, image.Width, image.Height), image); uint textureId = 0; /*textureId = new uint[1]; textureId[0]= 0; GL.GenTextures(1,textureId);*/ GL.GenTextures(1, ref textureId); GL.BindTexture(All.Texture2D, textureId); GL.TexParameter(All.Texture2D, All.TextureMinFilter, (int)filter); GL.TexParameter(All.Texture2D, All.TextureMagFilter, (int)filter); GL.TexImage2D(All.Texture2D, 0, (int)All.Rgba, (int)potWidth, (int)potHeight, 0, All.Rgba, All.UnsignedByte, new IntPtr(data)); return new Texture2D(logicalSize.X, logicalSize.Y, pixelWidth, pixelHeight, potWidth, potHeight, textureId, name); } } } } }
private void InitWithCGImage(CGImage image, All filter) { int width, height, i; CGContext context = null; IntPtr data; CGColorSpace colorSpace; IntPtr tempData; bool hasAlpha; CGImageAlphaInfo info; CGAffineTransform transform; Size imageSize; SurfaceFormat pixelFormat; //bool sizeToFit = false; if (image == null) { throw new ArgumentException(" NSImage is invalid! "); } info = image.AlphaInfo; hasAlpha = ((info == CGImageAlphaInfo.PremultipliedLast) || (info == CGImageAlphaInfo.PremultipliedFirst) || (info == CGImageAlphaInfo.Last) || (info == CGImageAlphaInfo.First) ? true : false); if (image.ColorSpace != null) { if (hasAlpha) { pixelFormat = SurfaceFormat.Color; } else { pixelFormat = SurfaceFormat.Color; } } else { pixelFormat = SurfaceFormat.Alpha8; } imageSize = new Size(image.Width, image.Height); transform = CGAffineTransform.MakeIdentity(); width = imageSize.Width; // Take out the width and height adjustments for power of 2 // If not then GetData and SetData is messed up. // The Mac opengl version supports non power of 2 textures // so we do not have to make them so // if ((width != 1) && ((width & (width - 1)) != 0)) { // i = 1; // while ((sizeToFit ? 2 * i : i) < width) // i *= 2; // width = i; // } height = imageSize.Height; // The Mac opengl version supports non power of 2 textures // so we do not have to make them so // if ((height != 1) && ((height & (height - 1)) != 0)) { // i = 1; // while ((sizeToFit ? 2 * i : i) < height) // i *= 2; // height = i; // } // TODO: kMaxTextureSize = 1024 // while ((width > 1024) || (height > 1024)) { // width /= 2; // height /= 2; // transform = CGAffineTransform.MakeScale (0.5f, 0.5f); // imageSize.Width /= 2; // imageSize.Height /= 2; // } // I am going to take the following out right now to see how it reacts. It seems to be causing // a few problems for people. We may need to come up with another way to solve these issues as // one size is not fitting all. // float size = Math.Max(width,height); // if(size > 1024) // { // float ratio = 1024 / size; // width = (int)(width * ratio); // height = (int)(height * ratio); // transform = CGAffineTransform.MakeScale(ratio, ratio); // imageSize.Width = (int)(imageSize.Width * ratio); // imageSize.Height = (int)(imageSize.Height * ratio);; // } switch (pixelFormat) { case SurfaceFormat.Color: colorSpace = CGColorSpace.CreateDeviceRGB(); data = Marshal.AllocHGlobal(height * width * 4); context = new CGBitmapContext(data, width, height, 8, 4 * width, colorSpace, CGImageAlphaInfo.PremultipliedLast); colorSpace.Dispose(); break; case SurfaceFormat.Alpha8: data = Marshal.AllocHGlobal(height * width); context = new CGBitmapContext(data, width, height, 8, width, null, CGImageAlphaInfo.Only); break; default: throw new NotSupportedException("Invalid pixel format"); } context.ClearRect(new RectangleF(0, 0, width, height)); context.TranslateCTM(0, height - imageSize.Height); if (!transform.IsIdentity) { context.ConcatCTM(transform); } context.DrawImage(new RectangleF(0, 0, image.Width, image.Height), image); //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" /* * if(pixelFormat == SurfaceFormat.Rgb32) { * tempData = Marshal.AllocHGlobal(height * width * 2); * * int d32; * short d16; * int inPixel32Count=0,outPixel16Count=0; * for(i = 0; i < width * height; ++i, inPixel32Count+=sizeof(int)) * { * d32 = Marshal.ReadInt32(data,inPixel32Count); * short R = (short)((((d32 >> 0) & 0xFF) >> 3) << 11); * short G = (short)((((d32 >> 8) & 0xFF) >> 2) << 5); * short B = (short)((((d32 >> 16) & 0xFF) >> 3) << 0); * d16 = (short) (R | G | B); * Marshal.WriteInt16(tempData,outPixel16Count,d16); * outPixel16Count += sizeof(short); * } * Marshal.FreeHGlobal(data); * data = tempData; * } */ InitWithData(data, pixelFormat, width, height, imageSize, filter); context.Dispose(); Marshal.FreeHGlobal(data); }
public static UIImage CorrectImageRotation(UIImage image) { UIImage imageToReturn = null; if (image.Orientation == UIImageOrientation.Up) { imageToReturn = image; } else { var transform = CGAffineTransform.MakeIdentity(); switch (image.Orientation) { case UIImageOrientation.Down: case UIImageOrientation.DownMirrored: transform.Rotate((float)Math.PI); transform.Translate(image.Size.Width, image.Size.Height); break; case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: transform.Rotate((float)Math.PI / 2); transform.Translate(image.Size.Width, 0); break; case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: transform.Rotate(-(float)Math.PI / 2); transform.Translate(0, image.Size.Height); break; case UIImageOrientation.Up: case UIImageOrientation.UpMirrored: break; } switch (image.Orientation) { case UIImageOrientation.UpMirrored: case UIImageOrientation.DownMirrored: transform.Translate(image.Size.Width, 0); transform.Scale(-1, 1); break; case UIImageOrientation.LeftMirrored: case UIImageOrientation.RightMirrored: transform.Translate(image.Size.Height, 0); transform.Scale(-1, 1); break; case UIImageOrientation.Up: case UIImageOrientation.Down: case UIImageOrientation.Left: case UIImageOrientation.Right: break; } using var context = new CGBitmapContext( IntPtr.Zero, (int)image.Size.Width, (int)image.Size.Height, image.CGImage.BitsPerComponent, image.CGImage.BytesPerRow, image.CGImage.ColorSpace, image.CGImage.BitmapInfo); context.ConcatCTM(transform); switch (image.Orientation) { case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: context.DrawImage(new CGRect(0, 0, image.Size.Height, image.Size.Width), image.CGImage); break; default: context.DrawImage(new CGRect(0, 0, image.Size.Width, image.Size.Height), image.CGImage); break; } using var imageRef = context.ToImage(); imageToReturn = new UIImage(imageRef, 1, UIImageOrientation.Up); } return(imageToReturn); }
public static Stream RotateImage(UIImage image) { UIImage imageToReturn = null; if (image.Orientation == UIImageOrientation.Up) { imageToReturn = image; } else { CGAffineTransform transform = CGAffineTransform.MakeIdentity(); switch (image.Orientation) { case UIImageOrientation.Down: case UIImageOrientation.DownMirrored: transform.Rotate((float)Math.PI); transform.Translate(image.Size.Width, image.Size.Height); break; case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: transform.Rotate((float)Math.PI / 2); transform.Translate(image.Size.Width, 0); break; case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: transform.Rotate(-(float)Math.PI / 2); transform.Translate(0, image.Size.Height); break; case UIImageOrientation.Up: case UIImageOrientation.UpMirrored: break; } switch (image.Orientation) { case UIImageOrientation.UpMirrored: case UIImageOrientation.DownMirrored: transform.Translate(image.Size.Width, 0); transform.Scale(-1, 1); break; case UIImageOrientation.LeftMirrored: case UIImageOrientation.RightMirrored: transform.Translate(image.Size.Height, 0); transform.Scale(-1, 1); break; case UIImageOrientation.Up: case UIImageOrientation.Down: case UIImageOrientation.Left: case UIImageOrientation.Right: break; } using (var context = new CGBitmapContext(IntPtr.Zero, (int)image.Size.Width, (int)image.Size.Height, image.CGImage.BitsPerComponent, image.CGImage.BytesPerRow, image.CGImage.ColorSpace, image.CGImage.BitmapInfo)) { context.ConcatCTM(transform); switch (image.Orientation) { case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: context.DrawImage(new RectangleF(PointF.Empty, new SizeF((float)image.Size.Height, (float)image.Size.Width)), image.CGImage); break; default: context.DrawImage(new RectangleF(PointF.Empty, new SizeF((float)image.Size.Width, (float)image.Size.Height)), image.CGImage); break; } using (var imageRef = context.ToImage()) { imageToReturn = new UIImage(imageRef); } } } return(imageToReturn.AsJPEG().AsStream()); }
UIImage FixOrientation(UIImage image) { // It's portrait. if (image.Orientation == UIImageOrientation.Up) { return(image); } var transform = CGAffineTransform.MakeIdentity(); switch (image.Orientation) { case UIImageOrientation.Down: case UIImageOrientation.DownMirrored: transform = CGAffineTransform.Translate(transform, image.Size.Width, image.Size.Height); transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI); break; case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: transform = CGAffineTransform.Translate(transform, image.Size.Width, 0); transform = CGAffineTransform.Rotate(transform, (nfloat)(Math.PI / 2)); break; case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: transform = CGAffineTransform.Translate(transform, 0, image.Size.Height); transform = CGAffineTransform.Rotate(transform, (nfloat)(-Math.PI / 2)); break; default: break; } switch (image.Orientation) { case UIImageOrientation.UpMirrored: case UIImageOrientation.DownMirrored: transform = CGAffineTransform.Translate(transform, image.Size.Width, 0); transform = CGAffineTransform.Scale(transform, -1, 1); break; case UIImageOrientation.LeftMirrored: case UIImageOrientation.RightMirrored: transform = CGAffineTransform.Translate(transform, image.Size.Height, 0); transform = CGAffineTransform.Scale(transform, -1, 1); break; default: break; } var ctx = new CGBitmapContext(IntPtr.Zero, (nint)image.Size.Width, (nint)image.Size.Height, image.CGImage.BitsPerComponent, 0, image.CGImage.ColorSpace, image.CGImage.BitmapInfo); ctx.ConcatCTM(transform); switch (image.Orientation) { case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: ctx.DrawImage(new CGRect(0, 0, image.Size.Height, image.Size.Width), image.CGImage); break; default: ctx.DrawImage(new CGRect(0, 0, image.Size.Width, image.Size.Height), image.CGImage); break; } var cgimg = ctx.ToImage(); var img = UIImage.FromImage(cgimg); ctx.Dispose(); cgimg.Dispose(); return(img); }
internal static void NativeDrawString(CGBitmapContext bitmapContext, string s, CTFont font, CCColor4B brush, RectangleF layoutRectangle) { if (font == null) { throw new ArgumentNullException("font"); } if (s == null || s.Length == 0) { return; } bitmapContext.ConcatCTM(bitmapContext.GetCTM().Invert()); // This is not needed here since the color is set in the attributed string. //bitmapContext.SetFillColor(brush.R/255f, brush.G/255f, brush.B/255f, brush.A/255f); // I think we only Fill the text with no Stroke surrounding //bitmapContext.SetTextDrawingMode(CGTextDrawingMode.Fill); var attributedString = buildAttributedString(s, font, brush); // Work out the geometry RectangleF insetBounds = layoutRectangle; PointF textPosition = new PointF(insetBounds.X, insetBounds.Y); float boundsWidth = insetBounds.Width; // Calculate the lines int start = 0; int length = attributedString.Length; var typesetter = new CTTypesetter(attributedString); float baselineOffset = 0; // First we need to calculate the offset for Vertical Alignment if we // are using anything but Top if (vertical != CCVerticalTextAlignment.Top) { while (start < length) { int count = typesetter.SuggestLineBreak(start, boundsWidth); var line = typesetter.GetLine(new NSRange(start, count)); // Create and initialize some values from the bounds. float ascent; float descent; float leading; line.GetTypographicBounds(out ascent, out descent, out leading); baselineOffset += (float)Math.Ceiling(ascent + descent + leading + 1); // +1 matches best to CTFramesetter's behavior line.Dispose(); start += count; } } start = 0; while (start < length && textPosition.Y < insetBounds.Bottom) { // Now we ask the typesetter to break off a line for us. // This also will take into account line feeds embedded in the text. // Example: "This is text \n with a line feed embedded inside it" int count = typesetter.SuggestLineBreak(start, boundsWidth); var line = typesetter.GetLine(new NSRange(start, count)); // Create and initialize some values from the bounds. float ascent; float descent; float leading; line.GetTypographicBounds(out ascent, out descent, out leading); // Calculate the string format if need be var penFlushness = 0.0f; if (horizontal == CCTextAlignment.Right) { penFlushness = (float)line.GetPenOffsetForFlush(1.0f, boundsWidth); } else if (horizontal == CCTextAlignment.Center) { penFlushness = (float)line.GetPenOffsetForFlush(0.5f, boundsWidth); } // initialize our Text Matrix or we could get trash in here var textMatrix = CGAffineTransform.MakeIdentity(); if (vertical == CCVerticalTextAlignment.Top) { textMatrix.Translate(penFlushness, insetBounds.Height - textPosition.Y - (float)Math.Floor(ascent - 1)); } if (vertical == CCVerticalTextAlignment.Center) { textMatrix.Translate(penFlushness, ((insetBounds.Height / 2) + (baselineOffset / 2)) - textPosition.Y - (float)Math.Floor(ascent - 1)); } if (vertical == CCVerticalTextAlignment.Bottom) { textMatrix.Translate(penFlushness, baselineOffset - textPosition.Y - (float)Math.Floor(ascent - 1)); } // Set our matrix bitmapContext.TextMatrix = textMatrix; // and draw the line line.Draw(bitmapContext); // Move the index beyond the line break. start += count; textPosition.Y += (float)Math.Ceiling(ascent + descent + leading + 1); // +1 matches best to CTFramesetter's behavior line.Dispose(); } }
public static Stream RotateImage(UIImage image) { UIImage imageToReturn = null; if (image.Orientation == UIImageOrientation.Up) { imageToReturn = image; } else { CGAffineTransform transform = CGAffineTransform.MakeIdentity(); switch (image.Orientation) { case UIImageOrientation.Down: case UIImageOrientation.DownMirrored: transform.Rotate((float)Math.PI); transform.Translate(image.Size.Width, image.Size.Height); break; case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: transform.Rotate((float)Math.PI / 2); transform.Translate(image.Size.Width, 0); break; case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: transform.Rotate(-(float)Math.PI / 2); transform.Translate(0, image.Size.Height); break; case UIImageOrientation.Up: case UIImageOrientation.UpMirrored: break; } switch (image.Orientation) { case UIImageOrientation.UpMirrored: case UIImageOrientation.DownMirrored: transform.Translate(image.Size.Width, 0); transform.Scale(-1, 1); break; case UIImageOrientation.LeftMirrored: case UIImageOrientation.RightMirrored: transform.Translate(image.Size.Height, 0); transform.Scale(-1, 1); break; case UIImageOrientation.Up: case UIImageOrientation.Down: case UIImageOrientation.Left: case UIImageOrientation.Right: break; } using (var context = new CGBitmapContext(IntPtr.Zero, (int)image.Size.Width, (int)image.Size.Height, image.CGImage.BitsPerComponent, image.CGImage.BytesPerRow, image.CGImage.ColorSpace, image.CGImage.BitmapInfo)) { context.ConcatCTM(transform); switch (image.Orientation) { case UIImageOrientation.Left: case UIImageOrientation.LeftMirrored: case UIImageOrientation.Right: case UIImageOrientation.RightMirrored: context.DrawImage(new RectangleF(PointF.Empty, new SizeF((float)image.Size.Height, (float)image.Size.Width)), image.CGImage); break; default: context.DrawImage(new RectangleF(PointF.Empty, new SizeF((float)image.Size.Width, (float)image.Size.Height)), image.CGImage); break; } using (var imageRef = context.ToImage()) { imageToReturn = new UIImage(imageRef); } } } var finalQuality = 1.0f; var imageData = image.AsJPEG(finalQuality); //continue to move down quality , rare instances while (imageData == null && finalQuality > 0) { finalQuality -= 0.05f; imageData = image.AsJPEG(finalQuality); } if (imageData == null) { throw new NullReferenceException("Unable to convert image to jpeg, please ensure file exists or lower quality level"); } var stream = imageData.AsStream(); imageData.Dispose(); return(stream); }
static string RenderPoint(XIR.Point point) { var base64 = string.Empty; var pointSize = new CGSize(8, 8); var rectangle = new CGRect(0, 0, 100, 100); var measure = CGSize.Empty; var line = GetLabel(string.Format("({0:0.########}, {1:0.###########})", point.X, point.Y), out measure); if (measure.Width > rectangle.Width) { rectangle.Size = new CGSize(measure.Width, measure.Width); } int width = (int)rectangle.Width; int height = (int)rectangle.Height; var bytesPerRow = 4 * width; using (var context = new CGBitmapContext( IntPtr.Zero, width, height, 8, bytesPerRow, CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedFirst)) { context.SetFillColor(BackgroundColor.CGColor); context.FillRect(rectangle); context.SetFillColor(pen.CGColor); var centerX = rectangle.GetMidX() - pointSize.Width / 2; var centerY = rectangle.GetMidY() - pointSize.Height / 2; context.FillEllipseInRect(new CGRect(centerX, centerY, pointSize.Width, pointSize.Height)); context.ConcatCTM(context.GetCTM().Invert()); var matrix = new CGAffineTransform( 1, 0, 0, -1, 0, height); context.ConcatCTM(matrix); var textMatrix = new CGAffineTransform( 1, 0, 0, -1, 0, 0); context.TextMatrix = textMatrix; context.TextPosition = new CGPoint(rectangle.GetMidX() - measure.Width / 2, rectangle.GetMidY() - (measure.Height * 2)); line.Draw(context); line.Dispose(); line = GetSubLabel("x, y", out measure); context.TextPosition = new CGPoint(rectangle.GetMidX() - measure.Width / 2, rectangle.GetMidY() - (measure.Height)); line.Draw(context); line.Dispose(); var bitmap = new NSBitmapImageRep(context.ToImage()); var data = bitmap.RepresentationUsingTypeProperties(NSBitmapImageFileType.Png); base64 = data.GetBase64EncodedString(NSDataBase64EncodingOptions.None); } return(String.Format( "<figure>" + "<figcaption>" + "Point: " + "<span class='var'>X</span> = <span class='value'>{0:0.########}</span>, " + "<span class='var'>Y</span> = <span class='value'>{1:0.########}</span>" + "</figcaption>" + "<img width='{2}' height='{3}' src='data:image/png;base64,{4}' />" + "</figure>", point.X, point.Y, (int)rectangle.Width, (int)rectangle.Height, base64 )); }
public void GetData <T>(int level, Rectangle?rect, T[] data, int startIndex, int elementCount) { if (data == null) { throw new ArgumentException("data cannot be null"); } if (data.Length < startIndex + elementCount) { throw new ArgumentException("The data passed has a length of " + data.Length + " but " + elementCount + " pixels have been requested."); } Rectangle r; if (rect != null) { r = rect.Value; } else { r = new Rectangle(0, 0, Width, Height); } int sz = 0; byte[] pixel = new byte[4]; int pos; IntPtr pixelOffset; // Get the Color values if ((typeof(T) == typeof(Color))) { // Load up texture into memory UIImage uiImage = UIImage.FromBundle(this.Name); if (uiImage == null) { throw new ContentLoadException("Error loading file via UIImage: " + Name); } CGImage image = uiImage.CGImage; if (image == null) { throw new ContentLoadException("Error with CGIamge: " + Name); } int width, height, i; CGContext context = null; IntPtr imageData; CGColorSpace colorSpace; IntPtr tempData; bool hasAlpha; CGImageAlphaInfo info; CGAffineTransform transform; Size imageSize; SurfaceFormat pixelFormat; bool sizeToFit = false; info = image.AlphaInfo; hasAlpha = ((info == CGImageAlphaInfo.PremultipliedLast) || (info == CGImageAlphaInfo.PremultipliedFirst) || (info == CGImageAlphaInfo.Last) || (info == CGImageAlphaInfo.First) ? true : false); if (image.ColorSpace != null) { pixelFormat = SurfaceFormat.Color; } else { pixelFormat = SurfaceFormat.Alpha8; } imageSize = new Size(image.Width, image.Height); transform = CGAffineTransform.MakeIdentity(); width = imageSize.Width; if ((width != 1) && ((width & (width - 1)) != 0)) { i = 1; while ((sizeToFit ? 2 * i : i) < width) { i *= 2; } width = i; } height = imageSize.Height; if ((height != 1) && ((height & (height - 1)) != 0)) { i = 1; while ((sizeToFit ? 2 * i : i) < height) { i *= 2; } height = i; } // TODO: kMaxTextureSize = 1024 while ((width > 1024) || (height > 1024)) { width /= 2; height /= 2; transform = CGAffineTransform.MakeScale(0.5f, 0.5f); imageSize.Width /= 2; imageSize.Height /= 2; } switch (pixelFormat) { case SurfaceFormat.Color: colorSpace = CGColorSpace.CreateDeviceRGB(); imageData = Marshal.AllocHGlobal(height * width * 4); context = new CGBitmapContext(imageData, width, height, 8, 4 * width, colorSpace, CGImageAlphaInfo.PremultipliedLast); colorSpace.Dispose(); break; case SurfaceFormat.Alpha8: imageData = Marshal.AllocHGlobal(height * width); context = new CGBitmapContext(imageData, width, height, 8, width, null, CGImageAlphaInfo.Only); break; default: throw new NotSupportedException("Invalid pixel format"); } context.ClearRect(new RectangleF(0, 0, width, height)); context.TranslateCTM(0, height - imageSize.Height); if (!transform.IsIdentity) { context.ConcatCTM(transform); } context.DrawImage(new RectangleF(0, 0, image.Width, image.Height), image); //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" /* * if(pixelFormat == SurfaceFormat.Rgb32) { * tempData = Marshal.AllocHGlobal(height * width * 2); * * int d32; * short d16; * int inPixel32Count=0,outPixel16Count=0; * for(i = 0; i < width * height; ++i, inPixel32Count+=sizeof(int)) * { * d32 = Marshal.ReadInt32(imageData,inPixel32Count); * short R = (short)((((d32 >> 0) & 0xFF) >> 3) << 11); * short G = (short)((((d32 >> 8) & 0xFF) >> 2) << 5); * short B = (short)((((d32 >> 16) & 0xFF) >> 3) << 0); * d16 = (short) (R | G | B); * Marshal.WriteInt16(tempData,outPixel16Count,d16); * outPixel16Count += sizeof(short); * } * Marshal.FreeHGlobal(imageData); * imageData = tempData; * } */ int count = 0; // Loop through and extract the data for (int y = r.Top; y < r.Bottom; y++) { for (int x = r.Left; x < r.Right; x++) { var result = new Color(0, 0, 0, 0); switch (this.Format) { case SurfaceFormat.Color /*kTexture2DPixelFormat_RGBA8888*/: case SurfaceFormat.Dxt3: sz = 4; pos = ((y * imageSize.Width) + x) * sz; pixelOffset = new IntPtr(imageData.ToInt64() + pos); Marshal.Copy(pixelOffset, pixel, 0, 4); result.R = pixel[0]; result.G = pixel[1]; result.B = pixel[2]; result.A = pixel[3]; break; case SurfaceFormat.Bgra4444 /*kTexture2DPixelFormat_RGBA4444*/: sz = 2; pos = ((y * imageSize.Width) + x) * sz; pixelOffset = new IntPtr(imageData.ToInt64() + pos); Marshal.Copy(pixelOffset, pixel, 0, 4); result.R = pixel[0]; result.G = pixel[1]; result.B = pixel[2]; result.A = pixel[3]; break; case SurfaceFormat.Bgra5551 /*kTexture2DPixelFormat_RGB5A1*/: sz = 2; pos = ((y * imageSize.Width) + x) * sz; pixelOffset = new IntPtr(imageData.ToInt64() + pos); Marshal.Copy(pixelOffset, pixel, 0, 4); result.R = pixel[0]; result.G = pixel[1]; result.B = pixel[2]; result.A = pixel[3]; break; case SurfaceFormat.Alpha8 /*kTexture2DPixelFormat_A8*/: sz = 1; pos = ((y * imageSize.Width) + x) * sz; pixelOffset = new IntPtr(imageData.ToInt64() + pos); Marshal.Copy(pixelOffset, pixel, 0, 4); result.A = pixel[0]; break; default: throw new NotSupportedException("Texture format"); } data[((y * imageSize.Width) + x)] = (T)(object)result; count++; if (count >= elementCount) { return; } } } context.Dispose(); Marshal.FreeHGlobal(imageData); } else { throw new NotImplementedException(); } }
static string RenderSize(XIR.Size size) { var base64 = string.Empty; // We want the absolute values of the size var workSize = new CGSize(Math.Abs(size.Width), Math.Abs(size.Height)); // This is our scale factor for output var dstSize = new CGSize(50, 50); // Define our Height label variables var numHeightLabelBounds = CGSize.Empty; var heightLabelBounds = CGSize.Empty; var heightBounds = CGSize.Empty; // Obtain our label lines and bounding boxes of the labels var numHeightLine = GetLabel(string.Format("{0:0.########}", size.Height), out numHeightLabelBounds); var heightLine = GetSubLabel("Height", out heightLabelBounds); heightBounds.Width = NMath.Max(numHeightLabelBounds.Width, heightLabelBounds.Width); heightBounds.Height = NMath.Max(numHeightLabelBounds.Height, heightLabelBounds.Height); // Define our Width label variables var numWidthLabelBounds = CGSize.Empty; var widthLabelBounds = CGSize.Empty; var widthBounds = CGSize.Empty; // Obtain our label lines and bound boxes of the labels var numWidthLine = GetLabel(string.Format("{0:0.########}", size.Width), out numWidthLabelBounds); var widthLine = GetSubLabel("Width", out widthLabelBounds); widthBounds.Width = NMath.Max(numWidthLabelBounds.Width, widthLabelBounds.Width); widthBounds.Height = NMath.Max(numWidthLabelBounds.Height, widthLabelBounds.Height); // Calculate our scale based on our destination size var ratio = 1f; if (workSize.Width > workSize.Height) { ratio = (float)workSize.Height / (float)workSize.Width; dstSize.Height = (int)(dstSize.Height * ratio); } else { ratio = (float)workSize.Width / (float)workSize.Height; dstSize.Width = (int)(dstSize.Width * ratio); } // Make sure we at least have something to draw if the values are very small dstSize.Width = NMath.Max(dstSize.Width, 4f); dstSize.Height = NMath.Max(dstSize.Height, 4f); // Define graphic element sizes and offsets const int lineWidth = 2; const float capSize = 8f; const float vCapIndent = 3f; const float separationSpace = 2f; var extraBoundingSpaceWidth = (widthBounds.Width + separationSpace) * 2; var extraBoundingSpaceHeight = (heightBounds.Height + separationSpace) * 2; int width = (int)(dstSize.Width + lineWidth + capSize + vCapIndent + extraBoundingSpaceWidth); int height = (int)(dstSize.Height + lineWidth + capSize + extraBoundingSpaceHeight); var bytesPerRow = 4 * width; using (var context = new CGBitmapContext( IntPtr.Zero, width, height, 8, bytesPerRow, CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedFirst)) { // Clear the context with our background color context.SetFillColor(BackgroundColor.CGColor); context.FillRect(new CGRect(0, 0, width, height)); // Setup our matrices so our 0,0 is top left corner. Just makes it easier to layout context.ConcatCTM(context.GetCTM().Invert()); var matrix = new CGAffineTransform( 1, 0, 0, -1, 0, height); context.ConcatCTM(matrix); context.SetStrokeColor(pen.CGColor); context.SetLineWidth(lineWidth); context.SaveState(); // We need to offset the drawing of our size segment rulers leaving room for labels var xOffSet = heightBounds.Width; var yOffset = (height - extraBoundingSpaceHeight) / 2f - dstSize.Height / 2f; context.TranslateCTM(xOffSet, yOffset); // Draw the Height segment ruler var vCapCenter = vCapIndent + (capSize / 2f); context.AddLines(new CGPoint[] { new CGPoint(vCapIndent, 1), new CGPoint(vCapIndent + capSize, 1), new CGPoint(vCapCenter, 1), new CGPoint(vCapCenter, dstSize.Height), new CGPoint(vCapIndent, dstSize.Height), new CGPoint(vCapIndent + capSize, dstSize.Height), }); // Draw the Width segment ruler var hCapIndent = vCapIndent + capSize + separationSpace; var hCapOffsetY = dstSize.Height; var hCapCenter = hCapOffsetY + (capSize / 2f); context.AddLines(new CGPoint[] { new CGPoint(hCapIndent, hCapOffsetY), new CGPoint(hCapIndent, hCapOffsetY + capSize), new CGPoint(hCapIndent, hCapCenter), new CGPoint(hCapIndent + dstSize.Width, hCapCenter), new CGPoint(hCapIndent + dstSize.Width, hCapOffsetY), new CGPoint(hCapIndent + dstSize.Width, hCapOffsetY + capSize), }); context.StrokePath(); context.RestoreState(); // Setup our text matrix var textMatrix = new CGAffineTransform( 1, 0, 0, -1, 0, 0); context.TextMatrix = textMatrix; // Draw the Height label context.TextPosition = new CGPoint(heightBounds.Width / 2 - numHeightLabelBounds.Width / 2, height / 2 - heightBounds.Height / 2); numHeightLine.Draw(context); context.TextPosition = new CGPoint(heightBounds.Width / 2 - heightLabelBounds.Width / 2, height / 2 + heightBounds.Height / 2); heightLine.Draw(context); // Draw the Width label var widthOffsetX = heightBounds.Width - separationSpace + dstSize.Width / 2; context.TextPosition = new CGPoint(widthOffsetX + (widthBounds.Width / 2 - numWidthLabelBounds.Width / 2), height - widthBounds.Height - 2); numWidthLine.Draw(context); context.TextPosition = new CGPoint(widthOffsetX + (widthBounds.Width / 2 - widthLabelBounds.Width / 2), height - widthLabelBounds.Height / 2); widthLine.Draw(context); // Get rid of our lines numHeightLine.Dispose(); heightLine.Dispose(); numWidthLine.Dispose(); widthLine.Dispose(); // Convert to base64 for display var bitmap = new NSBitmapImageRep(context.ToImage()); var data = bitmap.RepresentationUsingTypeProperties(NSBitmapImageFileType.Png); base64 = data.GetBase64EncodedString(NSDataBase64EncodingOptions.None); } return(String.Format("" + "<figure>" + "<figcaption>" + "Size: " + "<span class='var'>Width</span> = <span class='value'>{0:0.########}</span>, " + "<span class='var'>Height</span> = <span class='value'>{1:0.########}</span>" + "</figcaption>" + "<img width='{2}' height='{3}' src='data:image/png;base64,{4}' />" + "</figure>", size.Width, size.Height, (int)width, (int)height, base64 )); }