// Convert bitmap: // 1. Trim to square // 2. Resize to 28x28 pixels // 3. Grayscale with high contrast SKBitmap ConvertBitmap(SKBitmap bitmap, float contr = contrast) { // 0. bitmap initialized? if (bitmap == null) { return(null); } // 1. Square bitmap (if not done by media plugin) if (bitmap.Width != bitmap.Height) { // Calculate size and start coordinates of square int size = Math.Min(bitmap.Width, bitmap.Height); int left = (bitmap.Width - size) / 2; int top = (bitmap.Height - size) / 2; // Cut centered square bitmap.ExtractSubset(bitmap, new SKRectI(left, top, left + size, top + size)); } // 2. Resize to 28x28 pixels (if not done by media plugin) if (bitmap.Width != 28) { SKBitmap bitmap_copy = bitmap.Copy(); bitmap = new SKBitmap(28, 28, bitmap.ColorType, bitmap.AlphaType); bitmap_copy.Resize(bitmap, SKBitmapResizeMethod.Box); } // 3. Convert bitmap to grayscale and apply contrast to emphasize lines // Second grayscale conversion to highlight pen color again which may be suppressed by resizing bitmap = ConvertBitmapToGray(bitmap, contr); return(bitmap); }
// Working with a fix sized texture (512x512, 1024x1024, etc.). public Texture(SKBitmap image) { bmp = image.Copy(); this.width = bmp.Width; this.height = bmp.Height; internalBuffer = (byte *)bmp.GetPixels(); }
private static SKBitmap LoadFile(string filepath) { using var image = Pfim.Pfim.FromFile(filepath); if (image.Format != Pfim.ImageFormat.Rgba32 || image.Compressed) { throw new InvalidOperationException("Unexpected image format"); } var info = new SKImageInfo(image.Width, image.Height, SKColorType.Bgra8888, SKAlphaType.Unpremul); unsafe { fixed(byte *pData = image.Data) { using var bmp = new SKBitmap(info); if (!bmp.InstallPixels(info, (IntPtr)pData, image.Stride)) { throw new InvalidOperationException("Failed to load pixmap content"); } //Copying the bitmap seems to be the only reliable way to avoid //AccessViolationExceptions in Skia, even though we created it above return(bmp.Copy()); } } }
public IImageBuffer SKBitmapToImageBuffer(SKBitmap bitmap) { if (bitmap == null) { return(null); } if (bitmap.ColorType != SKColorType.Rgba8888 && bitmap.ColorType != SKColorType.Bgra8888 && bitmap.ColorType != SKColorType.Gray8) { // try to convert image to 32BPP bitmap if source pixel format is unknown if (!bitmap.CanCopyTo(SKColorType.Rgba8888)) { throw new NotSupportedException("SKImage Input pixel format not supported."); } using (bitmap = bitmap.Copy(SKColorType.Rgba8888)) { return(ToImageBuffer(bitmap)); } } else { return(ToImageBuffer(bitmap)); } }
/// <summary> /// Crop the image to fit within the dimensions specified. /// </summary> /// <param name="original"></param> /// <param name="maxSize"></param> /// <returns></returns> private SKBitmap Crop(SKBitmap original, SKSize maxSize) { var cropSides = 0; var cropTopBottom = 0; // calculate amount of pixels to remove from sides and top/bottom if ((float)maxSize.Width / original.Width < maxSize.Height / original.Height) // crop sides { cropSides = original.Width - (int)Math.Round((float)original.Height / maxSize.Height * maxSize.Width); } else { cropTopBottom = original.Height - (int)Math.Round((float)original.Width / maxSize.Width * maxSize.Height); } if (cropSides > 0 || cropTopBottom > 0) { // setup crop rect var cropRect = new SKRectI { Left = cropSides / 2, Top = cropTopBottom / 2, Right = original.Width - cropSides + cropSides / 2, Bottom = original.Height - cropTopBottom + cropTopBottom / 2 }; return(Crop(original, cropRect)); } else { return(original.Copy()); } }
/// <summary> /// Returns Texture Atlas' Bitmap /// </summary> /// <param name="colorType">The color type of the resulting bitmap</param> /// <returns>The texture atlas' bitmap</returns> private SKBitmap GetBitmap(SKColorType colorType = SKColorType.Rgba8888) { using (SKBitmap bmp = new SKBitmap(Width, Height, colorType, SKAlphaType.Premul)) //Premul needed for transparency ! { bmp.Erase(SKColors.Transparent); //DIDNT WORK WITHOUT THIS !!!! ctor of SKBitmap sometimes returned bitmap that was not clear .. //When clicked several times on Generate atlas (with for example genetic, maxIterations 12300) using (SKCanvas canvas = new SKCanvas(bmp)) { foreach (var img in Rects) { canvas.DrawBitmap(img.Image.Bitmap, img.Rect); } } //It may return Null, if SKColorType == Unknown, as it is not supported now var res = bmp.Copy(); //We have to return copy because we do not want to allow someone who got the bitmap to write into it if (res == null) { res = new SKBitmap(Width, Height); res.Erase(SKColors.Transparent); } return(res); } }
public IBitmap Clone(PixelFormat format) { if (_bitmap != null) { return(new SkiaBitmap(_bitmap.Copy(format.ToSKColorType()))); } return(null); }
public static SKBitmap HandleOrientation(SKBitmap bitmap, ExifOrientation exifOrientation) { SKBitmap rotated; switch (exifOrientation) { case ExifOrientation.Rotate180: using (var surface = new SKCanvas(bitmap)) { surface.RotateDegrees(180, bitmap.Width / 2, bitmap.Height / 2); surface.DrawBitmap(bitmap.Copy(), 0, 0); } return(bitmap); case ExifOrientation.MirrorHorizontal: rotated = new SKBitmap(bitmap.Height, bitmap.Width); using (var surface = new SKCanvas(rotated)) { surface.Translate(rotated.Width, 0); surface.RotateDegrees(90); surface.DrawBitmap(bitmap, 0, 0); } return(rotated); case ExifOrientation.MirrorVertical: rotated = new SKBitmap(bitmap.Height, bitmap.Width); using (var surface = new SKCanvas(rotated)) { surface.Translate(0, rotated.Height); surface.RotateDegrees(270); surface.DrawBitmap(bitmap, 0, 0); } return(rotated); case ExifOrientation.Rotate90: rotated = new SKBitmap(bitmap.Height, bitmap.Width); using (var surface = new SKCanvas(rotated)) { surface.Translate(rotated.Width, 0); surface.RotateDegrees(90); surface.DrawBitmap(bitmap, 0, 0); } return(rotated); default: return(bitmap); } }
public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, int width, int height, int stride) { using (var tmp = new SKBitmap()) { tmp.InstallPixels(new SKImageInfo(width, height, format.ToSkColorType(), SKAlphaType.Premul) , data, stride); return(new BitmapImpl(tmp.Copy())); } }
/// <summary> /// Resize using SkiaSharp - this can do 100 images in about 30s (2020 i5 MacBook Air). /// </summary> /// <param name="source"></param> /// <param name="destFiles"></param> public void CreateThumbs(FileInfo source, IDictionary <FileInfo, ThumbConfig> destFiles, out string imageHash) { try { int desiredWidth = destFiles.Max(x => x.Value.width); using var sourceBitmap = LoadOrientedBitmap(source, desiredWidth); imageHash = GetHash(sourceBitmap); Stopwatch thumbs = new Stopwatch("SkiaSharpThumbs"); // Dropping this from High to Low doesn't have that much of an effect // in terms of performance. var quality = SKFilterQuality.Low; var srcBitmap = sourceBitmap; foreach (var pair in destFiles.OrderByDescending(x => x.Value.width)) { var dest = pair.Key; var config = pair.Value; float widthScaleFactor = (float)srcBitmap.Width / (float)config.width; float heighScaleFactor = (float)srcBitmap.Height / (float)config.height; float scaleFactor = Math.Min(widthScaleFactor, heighScaleFactor); using var scaledImage = new SKBitmap((int)(srcBitmap.Width / scaleFactor), (int)(srcBitmap.Height / scaleFactor)); srcBitmap.ScalePixels(scaledImage.PeekPixels(), quality); var cropSize = new SKSize { Height = config.height, Width = config.width }; using var cropped = config.cropToRatio ? Crop(scaledImage, cropSize) : scaledImage; using SKData data = cropped.Encode(SKEncodedImageFormat.Jpeg, 90); using (var stream = new FileStream(dest.FullName, FileMode.Create, FileAccess.Write)) data.SaveTo(stream); // Now, use the previous scaled image as the basis for the // next smaller thumbnail. This should reduce processing // time as we only work on the large image on the first // iteration srcBitmap = scaledImage.Copy(); // TODO: Dispose } thumbs.Stop(); } catch (Exception ex) { Logging.Log($"Exception during Skia processing: {ex.Message}"); throw; } }
private SKBitmap RotateBitmap(SKBitmap bitmap, int degrees) { using (var surface = new SKCanvas(bitmap)) { surface.RotateDegrees(degrees, bitmap.Width / 2, bitmap.Height / 2); surface.DrawBitmap(bitmap.Copy(), 0, 0); } return(bitmap); }
internal ImageEditorViewModel(SKBitmap bitmap, ImageEditorConfig config) { Config = config; cropperCanvas = new ImageCropperCanvasView(bitmap, config.CropAspectRatio); mainCanvas = new TouchManipulationCanvasView(config); mainCanvas.AddBitmapToCanvas(bitmap.Copy(), BitmapType.Main); mainCanvas.TextBitmapClicked += MainCanvas_TextBitmapClicked; mainCanvas.TrashEnabled += MainCanvas_TrashVisebled; ColorCollect = SkiaHelper.GetColors(); CropCollect = CropItem.GetCropItems(config.CanChangeCropAspectRatio); Message = config?.LoadingText; }
public static SKBitmap LayerImage(SKBitmap baseLayer, SKBitmap overLayer, int x, int y) { if (baseLayer == null) { return(overLayer); } var img = baseLayer.Copy(); var rect = new SKRect(x, y, overLayer.Width + x, overLayer.Height + y); using var gr = new SKCanvas(img); gr.DrawBitmap(overLayer, rect); return(img); }
/// <summary> /// Loads an image at a given path /// </summary> /// <remarks>Does not check for the existence of the image</remarks> /// <param name="path">Path of the image to be loaded</param> /// <returns>The loaded image</returns> private static PPImage FastLoad(string path) { SKBitmap result = null; using (var sr = File.OpenRead(path)) using (var stream = new SKManagedStream(sr)) { result = SKBitmap.Decode(stream); result = result.Copy(); } return(new PPImage(result, path)); }
internal ImageEditorViewModel(SKBitmap bitmap, ImageEditorConfig config) { Config = config; cropperCanvas = new ImageCropperCanvasView(bitmap, config.CropAspectRatio); mainCanvas = new TouchManipulationCanvasView(config); mainCanvas.AddBitmapToCanvas(bitmap.Copy(), BitmapType.Main); mainCanvas.TextBitmapClicked += MainCanvas_TextBitmapClicked; mainCanvas.TrashEnabled += MainCanvas_TrashVisebled; ColorCollect = SkiaHelper.GetColors(); CropCollect = CropItem.GetCropItems(config.CanChangeCropAspectRatio); Message = config?.LoadingText; MessagingCenter.Subscribe <Xamarin.Forms.Application>(this, "BBDroidBackButton", (sender) => OnBackPressed()); }
public static SKBitmap ChangeAllColorTo(SKBitmap img, SKColor c) { if (img == null) { return(null); } var bmp = img.Copy(); var data = GetBitmapData(img); ChangeAllColorTo(data, c); SetBitmapData(bmp, data); return(bmp); }
public static SKBitmap ChangeOpacity(SKBitmap img, double trans) { if (img == null) { return(null); } var bmp = img.Copy(); var data = GetBitmapData(img); SetAllTransparencyTo(data, trans); SetBitmapData(bmp, data); return(bmp); }
public static SKBitmap ToGrayscale(SKBitmap img) { if (img == null) { return(null); } var bmp = img.Copy(); var data = GetBitmapData(img); SetAllColorToGrayScale(data); SetBitmapData(bmp, data); return(bmp); }
F9PImageData(SKBitmap skBitamp, string key) { RangeLists = skBitamp.PatchRanges(); if (RangeLists?.PatchesX != null && RangeLists.PatchesX.Count > 0 && RangeLists.PatchesY != null && RangeLists.PatchesY.Count > 0) { SKBitmap unmarkedBitmap = new SKBitmap(skBitamp.Width - 1, skBitamp.Height - 1, SKColorType.Rgba8888, SKAlphaType.Unpremul); skBitamp.ExtractSubset(unmarkedBitmap, SKRectI.Create(1, 1, skBitamp.Width - 2, skBitamp.Height - 2)); skBitamp.Dispose(); skBitamp = unmarkedBitmap.Copy(); } _width = skBitamp.Width; _height = skBitamp.Height; SKBitmap = skBitamp; Key = key; }
private static SKBitmap AutoOrient(SKBitmap bitmap, SKEncodedOrigin origin) { Stopwatch orient = new Stopwatch("SkiaSharpOrient"); SKBitmap rotated; switch (origin) { case SKEncodedOrigin.BottomRight: rotated = new SKBitmap(bitmap.Height, bitmap.Width); using (var canvas = new SKCanvas(rotated)) { canvas.RotateDegrees(180, bitmap.Width / 2, bitmap.Height / 2); canvas.DrawBitmap(bitmap, 0, 0); } break; case SKEncodedOrigin.RightTop: rotated = new SKBitmap(bitmap.Height, bitmap.Width); using (var canvas = new SKCanvas(rotated)) { canvas.Translate(rotated.Width, 0); canvas.RotateDegrees(90); canvas.DrawBitmap(bitmap, 0, 0); } break; case SKEncodedOrigin.LeftBottom: rotated = new SKBitmap(bitmap.Height, bitmap.Width); using (var canvas = new SKCanvas(rotated)) { canvas.Translate(0, rotated.Height); canvas.RotateDegrees(270); canvas.DrawBitmap(bitmap, 0, 0); } break; default: rotated = bitmap.Copy(); break; } orient.Stop(); return(rotated); }
public void QueueLoad(string tex, SKBitmap image) { if (textures.ContainsKey(tex)) { return; } if (image.ColorType != SKColorType.Bgra8888) { SKBitmap img; using (image) { img = image.Copy(SKColorType.Bgra8888); } image = img; } loadTexQueue[tex] = image; }
private async void SKElement_OnPaintSurface(object sender, SKPaintSurfaceEventArgs e) { Debug.WriteLine($"Enter OnPaintSurface: ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); if (backgroundTask == null) { backgroundTask = Task.Run(() => { Debug.WriteLine($"Enter Background: ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); using (var bitmap = new SKBitmap(e.Info.Width, e.Info.Height)) { using (var canvas = new SKCanvas(bitmap)) using (var paint = new SKPaint()) { canvas.DrawCircle(e.Info.Width / 2f, e.Info.Height / 2f, 100, paint); } return(bitmap.Copy()); } }); } else { // When task is awaited below we will get a second call to this method but we just ignore that for now Debug.WriteLine($"Exit OnPaintSurface Because Background Processing: ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); return; } if (backgroundTask != null) { Debug.WriteLine($"Before Background Await: ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); backgroundBitmap = await backgroundTask; Debug.WriteLine($"After Background Await: ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); } if (backgroundBitmap != null) { Debug.WriteLine($"DrawBitmap: ReadyToDraw={backgroundBitmap.ReadyToDraw}"); Debug.WriteLine($"DrawBitmap: ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); // This call will throw an AccessViolationException, but why? e.Surface.Canvas.DrawBitmap(backgroundBitmap, 0, 0); } }
// Got the code from https://stackoverflow.com/a/45620498/1074470 private static SKBitmap HandleOrientation(SKBitmap bitmap, SKCodecOrigin orientation) { SKBitmap rotated; switch (orientation) { case SKCodecOrigin.BottomRight: using (var surface = new SKCanvas(bitmap)) { surface.RotateDegrees(180, bitmap.Width / 2, bitmap.Height / 2); surface.DrawBitmap(bitmap.Copy(), 0, 0); } return(bitmap); case SKCodecOrigin.RightTop: rotated = new SKBitmap(bitmap.Height, bitmap.Width); using (var surface = new SKCanvas(rotated)) { surface.Translate(rotated.Width, 0); surface.RotateDegrees(90); surface.DrawBitmap(bitmap, 0, 0); } return(rotated); case SKCodecOrigin.LeftBottom: rotated = new SKBitmap(bitmap.Height, bitmap.Width); using (var surface = new SKCanvas(rotated)) { surface.Translate(0, rotated.Height); surface.RotateDegrees(270); surface.DrawBitmap(bitmap, 0, 0); } return(rotated); default: return(bitmap); } }
private SKBitmap DrawFrame(Model model) { SKBitmap currentFrame = new SKBitmap(1602, 1050); switch (model.Layout) { case LayoutType.Normal: currentFrame = DrawNormal(model); _lastframe = currentFrame; _lostHpCheckpoint = model.SideData.Health > previousHP ? 0 : model.SideData.Health == previousHP ? _lostHpCheckpoint : previousHP; _lostMpCheckpoint = model.SideData.Magic > previousMP ? 0 : model.SideData.Magic == previousMP ? _lostMpCheckpoint : previousMP; previousHP = model.SideData.Health; previousMP = model.SideData.Magic; break; case LayoutType.ConsoleSwitch: currentFrame = DrawConsoleSwitch(model); _lastframe = currentFrame; _lostHpCheckpoint = model.SideData.Health > previousHP ? 0 : model.SideData.Health; _lostMpCheckpoint = model.SideData.Magic > previousMP ? 0 : model.SideData.Magic; previousHP = model.SideData.Health; previousMP = model.SideData.Magic; break; case LayoutType.TextOnly: currentFrame = DrawTextBox(model, _lastframe); break; case LayoutType.MapOnly: currentFrame = DrawMap(model); break; case LayoutType.ConsoleFull: currentFrame = DrawConsoleFull(model); break; default: break; } SKBitmap forupdate = currentFrame.Copy(); return(forupdate); }
private SKBitmap DrawTextBox(Model model, SKBitmap lastframe) { SKBitmap overlayImage = lastframe.Copy(); using (SKCanvas g = new SKCanvas(overlayImage)) { var font = new SKPaint { Typeface = SKTypeface.FromFamilyName("Courier New"), TextSize = 12, IsAntialias = true, }; var darkPen = new SKPaint() { Color = SKColors.Black, StrokeWidth = 2, Style = SKPaintStyle.StrokeAndFill }; var rect2 = new SKRect(25, 25, 25 + 1000, 25 + 430); g.DrawRect(rect2, darkPen); darkPen = new SKPaint() { Color = new SKColor(255, 125, 98, 60), StrokeWidth = 2, Style = SKPaintStyle.Stroke }; g.DrawRect(rect2, darkPen); float x = 50; float y = 34; for (int i = 0; i < model.TileNames.Length; i++) { if (i % model.LineLength == 0)//next line { x = 50; y += 16; } g.WriteCharacter(model.TileNames[i], font, x, y); x += 12; } } return(overlayImage); }
public void Save(string fileName) { #if DESKTOP if (Bitmap.ColorType != SKColorType.Bgra8888) { using (var tmp = new BitmapImpl(Bitmap.Copy(SKColorType.Bgra8888))) tmp.Save(fileName); return; } IntPtr length; using (var sdb = new System.Drawing.Bitmap(PixelWidth, PixelHeight, Bitmap.RowBytes, System.Drawing.Imaging.PixelFormat.Format32bppArgb, Bitmap.GetPixels(out length))) sdb.Save(fileName); #else //SkiaSharp doesn't expose image encoders yet #endif }
/// <summary> /// Overlays 'overlayImage' over 'originalImage' with <see cref="CAMBlendMode"/> /// </summary> /// <returns>The resulting image.</returns> /// <param name="originalImage">The image to use as the background.</param> /// <param name="overlayImage">The image to overlay on the background.</param> public static SKBitmap OverlayImage(SKBitmap originalImage, SKBitmap overlayImage) { if (originalImage.Width != overlayImage.Width || originalImage.Height != overlayImage.Height) { String errorMessage = String.Format("originalImage and overlayImage are not the same dimensions: original ~ {0}x{1} | overlay ~ {2}x{3}", originalImage.Width, originalImage.Height, overlayImage.Width, overlayImage.Height); throw new ArgumentException(errorMessage); } SKBitmap output = originalImage.Copy(); SKCanvas skCanvas = new SKCanvas(output); SKPaint skPaint = new SKPaint(); skPaint.BlendMode = CAMBlendMode; skCanvas.DrawBitmap(overlayImage, 0, 0, skPaint); skCanvas.Flush(); return(output); }
/// <summary> /// Constructs an image from a given SKBitmap and obtains it's file name from a given pat /// </summary> /// <param name="skBmp">The SKBitmap from which an image should be created</param> /// <param name="filePath">The path of the image</param> /// <param name="isRotated">Whether the image is rotated by 90 degrees</param> public PPImage(SKBitmap skBmp, string filePath, bool isRotated = false) { if (skBmp == null) { throw new ArgumentNullException($"The {nameof(skBmp)} cannot be null"); } Bitmap = skBmp.Copy(); ImagePath = filePath; ImageName = System.IO.Path.GetFileName(filePath); OriginalWidth = FinalWidth = skBmp.Width; OriginalHeight = FinalHeight = skBmp.Height; NoWhiteSpaceXOffset = NoWhiteSpaceYOffset = 0; IsRotated = isRotated; Aliases = Enumerable.Empty <(string AliasedName, string AliasedPath)>(); bitmapHash = new Lazy <string>(() => { using (var sha = new SHA256Managed()) { return(Convert.ToBase64String(sha.ComputeHash(Bitmap.Bytes))); } }, true); }
public void Dispose() { using (var tmp = _bitmap.Copy(_nfo.ColorType)) tmp.CopyPixelsTo(_fb, _nfo.BytesPerPixel * _nfo.Height * _rowBytes, _rowBytes); _bitmap.Dispose(); }
///<inheritdoc/> public override Task InjectAsync(Stream source, Stream destination, Stream data, IProgress <double> progress = null, CancellationToken cancellationToken = default) { SKBitmap inputImage = SKBitmap.Decode(source); int width = inputImage.Width; int height = inputImage.Height; List <byte> ls_data = new List <byte>(); ls_data.AddRange(data.ReadAllBytes()); if (Eof != null) { ls_data.AddRange(Eof); } BitArray message = new BitArray(ls_data.ToArray()); int count = message.Count; if (EnsureSuccess) { int maxWritable = (UseAlphaChannel ? 4 : 3) * LsbDepth * width * height; if (count > maxWritable) { throw new InsufficientSpaceException("A successful write cannot be ensured because the data is too large"); } } SKBitmap outputImage = inputImage.Copy(); int pos = 0; for (int y = 0; y < height; y++) { bool stop = false; for (int x = 0; x < width; x++) { if (cancellationToken.IsCancellationRequested) { cancellationToken.ThrowIfCancellationRequested(); } if (pos == count) { stop = true; break; } SKColor pixel = inputImage.GetPixel(x, y); int[] vals = new int[] { pixel.Alpha, pixel.Red, pixel.Green, pixel.Blue }; for (int v = 0; v < vals.Length; v++) { if (!UseAlphaChannel && v == 0) { continue; } BitArray bitArray = new BitArray(new[] { vals[v] }); for (int i = 0; i < LsbDepth; i++) { if (pos == count) { stop = true; break; } bitArray[i] = message[pos]; pos++; } vals[v] = (int)bitArray.ToULong(); if (stop) { break; } } pixel = new SKColor((byte)vals[1], (byte)vals[2], (byte)vals[3], (byte)vals[0]); outputImage.SetPixel(x, y, pixel); if (progress != null) { progress.Report(pos / (double)count); } } if (stop) { break; } } outputImage.Encode(destination, SKEncodedImageFormat.Png, 100); return(Task.CompletedTask); }