public static bool FromGif(string srcFile, string outFile, Size size) { using (var sKCodec = SKCodec.Create(srcFile)) { using (var bitmap = new SKBitmap(sKCodec.Info)) { if (bitmap.Height > bitmap.Width) { size.Width = bitmap.Width * size.Height / bitmap.Height; } else { size.Height = bitmap.Height * size.Width / bitmap.Width; } sKCodec.GetPixels(sKCodec.Info, bitmap.GetPixels(), new SKCodecOptions(0)); using (var newBitmap = new SKBitmap(new SKImageInfo(size.Width, size.Height))) { bitmap.ScalePixels(newBitmap, SKFilterQuality.Medium); using (var image = SKImage.FromBitmap(newBitmap)) { using (var output = File.OpenWrite(outFile)) { image.Encode(SKEncodedImageFormat.Jpeg, 100) .SaveTo(output); return(true); } } } } } }
public void CanScalePixels() { var srcInfo = new SKImageInfo(200, 200); var dstInfo = new SKImageInfo(100, 100); var srcBmp = new SKBitmap(srcInfo); var dstBmp = new SKBitmap(dstInfo); using (var canvas = new SKCanvas(srcBmp)) using (var paint = new SKPaint { Color = SKColors.Green }) { canvas.Clear(SKColors.Blue); canvas.DrawRect(new SKRect(0, 0, 100, 200), paint); } Assert.Equal(SKColors.Green, srcBmp.GetPixel(75, 75)); Assert.Equal(SKColors.Blue, srcBmp.GetPixel(175, 175)); Assert.True(srcBmp.ScalePixels(dstBmp, SKFilterQuality.High)); Assert.Equal(SKColors.Green, dstBmp.GetPixel(25, 25)); Assert.Equal(SKColors.Blue, dstBmp.GetPixel(75, 75)); }
private SKBitmap Scale(SKBitmap input, int width, int height) { var info = new SKImageInfo(width, height); var newImg = SKImage.Create(info); input.ScalePixels(newImg.PeekPixels(), SKFilterQuality.Medium); return(SKBitmap.FromImage(newImg)); }
public static void mergeTiles(string folderPath) { if (folderPath.Last() == '/' || folderPath.Last() == '\\') { folderPath = folderPath.Remove(folderPath.Length - 1); } Dictionary <string, SKImage> images = new Dictionary <string, SKImage>(); int maxNumOfLevels = 3; for (int level = maxNumOfLevels; level > 0; --level) { int numOfTiles = Convert.ToInt32(Math.Pow(4, level - 1)); int tilesToASide = Convert.ToInt32(Math.Sqrt(numOfTiles)); for (int globaly = 0; globaly < tilesToASide; ++globaly) { for (int globalx = 0; globalx < tilesToASide; ++globalx) { var tempSurface = SKSurface.Create(new SKImageInfo(512, 512)); var canvas = tempSurface.Canvas; canvas.Clear(SKColors.Transparent); for (int tiley = 0; tiley < 2; ++tiley) { for (int tilex = 0; tilex < 2; ++tilex) { int imgx = (globalx * 2 + tilex); int imgy = (globaly * 2 + tiley); string tilePath = $"{folderPath}/aqlatestL{level}T{(globalx * 2 + tilex).ToString("D2")}{(globaly * 2 + tiley).ToString("D2")}.png"; string tileKey = $"L{level}T{(globalx * 2 + tilex).ToString("D2")}{(globaly * 2 + tiley).ToString("D2")}"; if (images.ContainsKey(tileKey)) { SKBitmap tile = SKBitmap.FromImage(images[tileKey]); canvas.DrawBitmap(tile, SKRect.Create(tilex * 256, tiley * 256, tile.Width, tile.Height)); } else if (File.Exists(tilePath)) { SKBitmap tile = SKBitmap.Decode(File.OpenRead(tilePath)); canvas.DrawBitmap(tile, SKRect.Create(tilex * 256, tiley * 256, tile.Width, tile.Height)); } } } SKBitmap bigTile = SKBitmap.FromImage(tempSurface.Snapshot()); SKBitmap littleTile = SKBitmap.FromImage(SKImage.Create(new SKImageInfo(256, 256))); bigTile.ScalePixels(littleTile, SKFilterQuality.High); SKImage outTile = SKImage.FromBitmap(littleTile); images.Add($"L{level - 1}T{globalx.ToString("D2")}{globaly.ToString("D2")}", outTile); } } } foreach (KeyValuePair <string, SKImage> file in images) { var data = file.Value.Encode(); var stream = File.OpenWrite($"{folderPath}/aqlatest{file.Key}.png"); data.SaveTo(stream); } }
private async Task RezPickedBitmap() { if (_userPickedBitmap == null) { return; } var rez = 100 + RezSlider.Value * 200; _applyDitherBitmap = new SKBitmap((int)rez, (int)(rez * (_userPickedBitmap.Height / (double)_userPickedBitmap.Width))); _userPickedBitmap.ScalePixels(_applyDitherBitmap, SKFilterQuality.None); }
/// <summary> /// Resize image to a specific size. /// </summary> /// <param name="width">Width.</param> /// <param name="height">Height.</param> /// <returns>New resized image.</returns> public IImage ResizeTo(int width, int height) { SKBitmap newBitmap = new SKBitmap(width, height); if (!bitmap.ScalePixels(newBitmap, SKFilterQuality.High)) { newBitmap.Dispose(); throw new ImageOperationException("SKBitmap.ScalePixels"); } return(new Image(newBitmap)); }
/// <summary> /// Pixelates a given image area defined by extractRect of the original image and draws it to the canvas. /// </summary> /// <param name="canvas"></param> /// <param name="extractRect"></param> /// <param name="original"></param> /// <param name="pixelSizeFunction"></param> private static void Pixelate(SKCanvas canvas, SKRectI extractRect, SKBitmap original, Func <int, int, int, int, int> pixelSizeFunction) { var pixelSize = pixelSizeFunction.Invoke(original.Width, original.Height, extractRect.Width, extractRect.Height); var downscaled = new SKBitmap(extractRect.Width / pixelSize, extractRect.Height / pixelSize); var upscaled = new SKBitmap(extractRect.Width, extractRect.Height); var sub = new SKBitmap(); original.ExtractSubset(sub, extractRect); sub.ScalePixels(downscaled, SKFilterQuality.None); downscaled.ScalePixels(upscaled, SKFilterQuality.None); canvas.DrawBitmap(upscaled, extractRect); }
internal static SKBitmap GetBlurBitmap(SKBitmap bitmap, SKRect rect) { SKBitmap outBitmap = new SKBitmap((int)rect.Width, (int)rect.Height); using (SKBitmap tempBitmap = new SKBitmap(CalcBackgraundBitmapsize(bitmap.Width), CalcBackgraundBitmapsize(bitmap.Height))) using (SKCanvas canvas = new SKCanvas(outBitmap)) using (SKPaint paint = new SKPaint()) { bitmap.ScalePixels(tempBitmap, SKFilterQuality.Low); paint.IsAntialias = true; float blur = 0.08f * Math.Max(rect.Width, rect.Height); blur = blur < 100 ? blur : 100; paint.ImageFilter = SKImageFilter.CreateBlur(blur, blur); canvas.Clear(); canvas.DrawBitmap(tempBitmap, rect, paint); } GC.Collect(0); return(outBitmap); }
/// <summary> /// <br>Encode the Input file Image, binarize it and save to an output file image</br> /// <br>Default image format: Png</br> /// </summary> /// <param name="inputFile">Input image path</param> /// <param name="outputFile">Output image path</param> /// <param name="encodingFormat">One of following formats is supported: Bmp, Gif, Ico, Jpeg, Png, Wbmp, Webp, Pkm, Ktx, Astc, Dng, Heif </param> public void EncodeAndSaveAsImage(string inputFile, string outputFile, string encodingFormat = "Png") { // // 1. Initiate the parameters this.binarizerParams.InputImagePath = inputFile; this.binarizerParams.OutputImagePath = outputFile; double[,,] binarizedImage = GetPixels(); // // 2. Reading the inputFile image to type SKBitmap SKBitmap inputBitmap = SKBitmap.Decode(inputFile); SKBitmap outputBitmap = new SKBitmap(binarizerParams.ImageWidth, binarizerParams.ImageHeight); inputBitmap.ScalePixels(outputBitmap, SKFilterQuality.High); for (int y = 0; y < outputBitmap.Height; y++) { for (int x = 0; x < outputBitmap.Width; x++) { int b = (int)binarizedImage[y, x, 0]; outputBitmap.SetPixel(x, y, new SKColor((byte)(255 * b), (byte)(255 * b), (byte)(255 * b))); } } // // 3. Reading a Picture file in pixels using (var image = SKImage.FromBitmap(outputBitmap)) { SKEncodedImageFormat frm = (SKEncodedImageFormat)Enum.Parse(typeof(SKEncodedImageFormat), encodingFormat); using (var data = image.Encode(frm, 80)) { // save the data to a stream using (var stream = File.OpenWrite($"{outputFile}")) { data.SaveTo(stream); } } } }
private unsafe void DecodeFrame(FastJavaByteArray fastArray) { if (input == null) { width = cameraController.LastCameraDisplayWidth; height = cameraController.LastCameraDisplayHeight; cDegrees = cameraController.LastCameraDisplayOrientationDegree; imageData = new int[width * height]; imageGCHandle = GCHandle.Alloc(imageData, GCHandleType.Pinned); imageIntPtr = imageGCHandle.AddrOfPinnedObject(); input = new SKBitmap(new SKImageInfo(width, height, SKColorType.Rgba8888)); input.InstallPixels(input.Info, imageIntPtr); } var pY = fastArray.Raw; var pUV = pY + width * height; stopwatch.Restart(); YuvHelper.ConvertYUV420SPToARGB8888(pY, pUV, (int *)imageIntPtr, width, height); stopwatch.Stop(); Stats.YUV2RGBElapsedMs = stopwatch.ElapsedMilliseconds; stopwatch.Restart(); input.ScalePixels(inputScaled, SKFilterQuality.None); RotateBitmap(inputScaled, cDegrees); stopwatch.Stop(); Stats.ResizeAndRotateElapsedMs = stopwatch.ElapsedMilliseconds; stopwatch.Restart(); tfService.Recognize(colors, colorCount); stopwatch.Stop(); Stats.InterpreterElapsedMs = stopwatch.ElapsedMilliseconds; MainActivity.ReloadCanvas(); }
private async Task DrawScaledUpImage() { if (_applyDitherBitmap == null) { return; } if (SkiaView.CanvasSize.Width > 0) { int newCanvasWidth = (int)SkiaView.CanvasSize.Width; int newCanvasHeight = (int)(SkiaView.CanvasSize.Width * (_applyDitherBitmap.Height / (double)_applyDitherBitmap.Width)); if ((int)SkiaView.CanvasSize.Width > (int)SkiaView.CanvasSize.Height) { newCanvasWidth = (int)(SkiaView.CanvasSize.Height * (_applyDitherBitmap.Width / (double)_applyDitherBitmap.Height)); newCanvasHeight = (int)SkiaView.CanvasSize.Height; } _drawBitmap = new SKBitmap(newCanvasWidth, newCanvasHeight); } _applyDitherBitmap.ScalePixels(_drawBitmap, SKFilterQuality.None); SkiaView.InvalidateSurface(); }
public static Dictionary <string, SKBitmap> GetEmotes(List <Comment> comments, string cacheFolder, Emotes embededEmotes = null, bool deepSearch = false) { Dictionary <string, SKBitmap> returnDictionary = new Dictionary <string, SKBitmap>(); List <string> alreadyAdded = new List <string>(); List <string> failedEmotes = new List <string>(); string emoteFolder = Path.Combine(cacheFolder, "emotes"); if (!Directory.Exists(emoteFolder)) { Directory.CreateDirectory(emoteFolder); } if (embededEmotes != null) { foreach (FirstPartyEmoteData emoteData in embededEmotes.firstParty) { try { if (!returnDictionary.ContainsKey(emoteData.id)) { returnDictionary.Add(emoteData.id, SKBitmap.Decode(emoteData.data)); alreadyAdded.Add(emoteData.id); } } catch { } } } using (WebClient client = new WebClient()) { foreach (var comment in comments) { if (comment.message.fragments == null) { continue; } foreach (var fragment in comment.message.fragments) { if (fragment.emoticon != null) { string id = fragment.emoticon.emoticon_id; if (!alreadyAdded.Contains(id) && !failedEmotes.Contains(id)) { try { string filePath = Path.Combine(emoteFolder, id + "_1x.png"); if (File.Exists(filePath)) { SKBitmap emoteImage = SKBitmap.Decode(filePath); if (emoteImage == null) { try { File.Delete(filePath); } catch { } } else { returnDictionary.Add(id, emoteImage); alreadyAdded.Add(id); } } if (!alreadyAdded.Contains(id)) { byte[] bytes = client.DownloadData(String.Format("https://static-cdn.jtvnw.net/emoticons/v1/{0}/1.0", id)); alreadyAdded.Add(id); MemoryStream ms = new MemoryStream(bytes); SKBitmap emoteImage = SKBitmap.Decode(ms); returnDictionary.Add(id, emoteImage); File.WriteAllBytes(filePath, bytes); } } catch (WebException) { string emoteName = fragment.text; bool foundEmote = false; if (deepSearch) { //lets try waybackmachine, very slow though :( try { for (int i = 1; i <= 3; i++) { JObject response = JObject.Parse(client.DownloadString($"https://archive.org/wayback/available?url=https://static-cdn.jtvnw.net/emoticons/v1/{id}/{i}.0/")); if (response["archived_snapshots"]["closest"] != null && response["archived_snapshots"]["closest"]["available"].ToObject <bool>() == true) { string filePath = Path.Combine(emoteFolder, id + "_1x.png"); byte[] bytes = client.DownloadData(response["archived_snapshots"]["closest"]["url"].ToString().Replace("/https://static-cdn.jtvnw.net", "if_/https://static-cdn.jtvnw.net")); MemoryStream ms = new MemoryStream(bytes); SKBitmap emoteImage = SKBitmap.Decode(ms); SKBitmap emoteImageScaled = new SKBitmap(28, 28); emoteImage.ScalePixels(emoteImageScaled, SKFilterQuality.High); alreadyAdded.Add(id); returnDictionary.Add(id, emoteImageScaled); emoteImage.Dispose(); emoteImageScaled.Encode(SKEncodedImageFormat.Png, 100).SaveTo(new FileStream(filePath, FileMode.Create)); foundEmote = true; break; } } } catch { } if (foundEmote) { continue; } else { //sometimes emote still exists but id is different, I use twitch metrics because I can't find an api to find an emote by name try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://www.twitchmetrics.net/e/" + emoteName); request.AllowAutoRedirect = false; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); string redirUrl = response.Headers["Location"]; response.Close(); string newId = redirUrl.Split('/').Last().Split('-').First(); byte[] bytes = client.DownloadData(String.Format("https://static-cdn.jtvnw.net/emoticons/v1/{0}/1.0", newId)); string filePath = Path.Combine(emoteFolder, id + "_1x.png"); File.WriteAllBytes(filePath, bytes); alreadyAdded.Add(id); MemoryStream ms = new MemoryStream(bytes); SKBitmap emoteImage = SKBitmap.Decode(ms); returnDictionary.Add(id, emoteImage); foundEmote = true; } catch { } } } if (!foundEmote) { failedEmotes.Add(id); } } } } } } } return(returnDictionary.Where(x => x.Value != null).ToDictionary(z => z.Key, z => z.Value)); }
static public MemoryStream Encode(FileStream surPicFile, FileStream insPicFile, string info, int compress) { if (compress == 0 || compress >= 8) { return(null); } byte[] lsbMask = { 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F }; char[] signature = "/By:f_Endman".ToCharArray(); long insPicLength = insPicFile.Length; SKBitmap surPic = SKBitmap.Decode(surPicFile); //得到隐写里图所需的表图的尺寸,并缩放表图 long byteForLSB = insPicLength * 8 / compress; //隐写所有里数据所需的表图字节数 long currentSurPicByte = surPic.Width * surPic.Height * 3; //表图现有的可用于LSB隐写的字节数 double zoom = (double)byteForLSB / (double)currentSurPicByte * ((compress >= 6) ? 1.05d : 1.01d); //表图需要缩放的倍数(留出1%-5%余量) /* 问题可转化为两矩形已知前后面积比例zoom,前者宽度高度a1,b1和a1/b1,并且两矩形长宽比相同即a1/b1=a2/b2;求后者矩形的长a2与宽b2 * * ∵a1/b1=a2/b2 ∴a2=a1/b1*b2 又∵a1*b1*zoom=a2*b2 ∴联立可解得b2=b1*根号zoom ∴a2=a1*根号zoom */ double squareRootZoom = Math.Sqrt(zoom); SKBitmap tankPic = new SKBitmap((int)(surPic.Width * squareRootZoom), (int)(surPic.Height * squareRootZoom), SKColorType.Bgra8888, SKAlphaType.Premul); surPic.ScalePixels(tankPic, SKFilterQuality.High); //为表图添加水印 SKPaint paint = new SKPaint { Color = SKColors.Black, TextSize = 24, IsAntialias = true, //抗锯齿 Typeface = SKTypeface.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("WarFactory.Resources.simhei.ttf")) //使用内嵌的字体 }; SKRect textSize = new SKRect(); paint.MeasureText(info, ref textSize); //得到文字的尺寸 int textWidth = (int)(textSize.Size.Width + 2); if (textWidth > tankPic.Width) { textWidth = tankPic.Width; } SKBitmap infoPic = new SKBitmap(textWidth, 30); //创建水印 SKCanvas canvas = new SKCanvas(infoPic); canvas.DrawColor(SKColors.White); canvas.DrawText(info, 0, (30 - textSize.Size.Height) / 2 - textSize.Top, paint); byte alpha = 0xCF; //水印不透明度 for (int i = 0; i < infoPic.Height; i++) //混色 { for (int j = 0; j < infoPic.Width; j++) { SKColor infoColor = infoPic.GetPixel(j, i); SKColor surColor = tankPic.GetPixel(j, i); byte red = (byte)((infoColor.Red * alpha + surColor.Red * (0xFF - alpha)) / 0xFF); byte green = (byte)((infoColor.Green * alpha + surColor.Green * (0xFF - alpha)) / 0xFF); byte blue = (byte)((infoColor.Blue * alpha + surColor.Blue * (0xFF - alpha)) / 0xFF); tankPic.SetPixel(j, i, new SKColor(red, green, blue)); } } //写入里数据文件头(根据网页源码以及WinHex亲测推测) /* 结构如下: * 里数据大小(字符串格式) * '\1' * 里文件名称 * '\1' * 里文件格式(特定字符串):目前我见过的原作者写的有"image/jpeg"和"image/png"和"image/png"三种,这个应该是关系到网页版解码后显示(我本业是嵌入式,让我完全弄明白这玩意就是难为我QWQ) * '\0' */ List <byte> insPicByteList = new List <byte>(); char[] insPicLengthStr = insPicLength.ToString().ToCharArray(); for (int i = 0; i < insPicLengthStr.Length; i++) { insPicByteList.Add((byte)insPicLengthStr[i]); } insPicByteList.Add(0x01); char[] insPicLengthFileName = insPicFile.Name.Substring(insPicFile.Name.LastIndexOf("/") + 1).ToCharArray(); //获取包含扩展名的文件名 for (int i = 0; i < insPicLengthFileName.Length; i++) { insPicByteList.Add((byte)insPicLengthFileName[i]); } insPicByteList.Add(0x01); char[] insMime; insMime = MimeUtility.GetMimeMapping(insPicFile.Name).ToCharArray(); for (int i = 0; i < insMime.Length; i++) { insPicByteList.Add((byte)insMime[i]); } insPicByteList.Add(0x00); //读取里数据 byte[] insPicByte = new byte[insPicFile.Length]; insPicFile.Read(insPicByte, 0, (int)insPicFile.Length); insPicFile.Seek(0, SeekOrigin.Begin); insPicByteList.AddRange(new List <byte>(insPicByte)); //BGRA转RGB SKColor[] tankColorArray = tankPic.Pixels; byte[] tankByteArray = new byte[tankColorArray.Length * 3]; for (int i = 0; i < tankColorArray.Length; i++) { tankByteArray[i * 3 + 0] = (tankColorArray[i].Red); tankByteArray[i * 3 + 1] = (tankColorArray[i].Green); tankByteArray[i * 3 + 2] = (tankColorArray[i].Blue); } //前三个字节为数据标识保留(根据网页源码推测) /* 原图数据前三个字节推测如下: * Byte[0]:低3位固定为0x0 * Byte[1]:低3位固定为0x3 * Byte[2]:低3位数据为LSB隐写的位数,对应网页版的压缩度 1 <= (Byte[2] & 0x7) <= 4 */ tankByteArray[0] &= 0xF8; tankByteArray[0] |= 0x00; tankByteArray[1] &= 0xF8; tankByteArray[1] |= 0x03; tankByteArray[2] &= 0xF8; tankByteArray[2] |= (byte)(compress & 0x7); //---LSB隐写,具体细节很繁琐,用到了一堆位运算---// int Count = 0, snCount = 0; Int32 FIFO = 0; //先进先出,用于缓存LSB int FifoCount = 0; //FIFO中剩余的要写入的LSB的数量 byte[] insPicByteArray = insPicByteList.ToArray(); //直接用List速度比较慢 insPicByteList.Clear(); for (int i = 3; i < tankByteArray.Length; i++) { if (FifoCount < compress) //FIFO不够写了就读一个字节 { //无影坦克的LSB是大端的,所以从"左"取数据,即先取高位 //如果里数据已经全部写入,就填充签名字符串 FIFO |= (Int32)(((Count < insPicByteArray.Length) ? insPicByteArray[Count++] : (byte)signature[snCount++ % signature.Length]) << (/* 32 - 8 */ 24 - FifoCount)); FifoCount += 8; } tankByteArray[i] &= (byte)~lsbMask[compress - 1]; //清除低n位 //无影坦克的LSB是大端的,所以从"左"取数据,即先取高位 tankByteArray[i] |= (byte)((FIFO >> (32 - compress)) & lsbMask[compress - 1]); FIFO <<= compress; FifoCount -= compress; } for (int i = 0; i < tankColorArray.Length; i++) { tankColorArray[i] = new SKColor(tankByteArray[i * 3 + 0], tankByteArray[i * 3 + 1], tankByteArray[i * 3 + 2]); } tankPic.Pixels = tankColorArray; byte[] tankPicArray = tankPic.Encode(SKEncodedImageFormat.Png, 100).ToArray(); surPicFile.Close(); surPicFile.Dispose(); insPicFile.Close(); insPicFile.Dispose(); return(new MemoryStream(tankPicArray)); }
/// <summary> /// Load an image from the phone /// </summary> /// <param name="sender"></param> /// <param name="args"></param> private async void LoadImage(object sender, EventArgs args) { IPhotoLibrary photoLibrary = DependencyService.Get <IPhotoLibrary>(); using (Stream stream = await photoLibrary.PickPhotoAsync()) { if (stream != null) { SKBitmap loaded = SKBitmap.Decode(stream); if (loaded != null) { if (animation) { StopAccelerometer(); } //Set the image dimensions width = (int)imgGenerated.CanvasSize.ToFormsSize().Width; height = (int)imgGenerated.CanvasSize.ToFormsSize().Height; int oldSize = width; if (width > height) { oldSize = height; } int size = oldSize; for (int i = 1; i < oldSize; i <<= 1) { size = i; } width = size; height = size; generator.SetDimensions(width, height); // Resize the loaded image //source: https://stackoverflow.com/questions/48422724/fastest-way-to-scale-an-skimage-skiasharp SKImageInfo info = new SKImageInfo(width, height, SKColorType.Rgba8888); SKImage output = SKImage.Create(info); loaded.ScalePixels(output.PeekPixels(), SKFilterQuality.None); imgBitmap = SKBitmap.FromImage(output); skRect = new SKRect(0, 0, oldSize, oldSize); generator.Load(imgBitmap); imgGenerated.InvalidateSurface(); if (animation) { StartAccelerometer(); } } } } }