public void TakeScreenshot(string filePath) { using Stream memStream = File.Open(filePath, FileMode.Create, FileAccess.Write, FileShare.None); using SKManagedWStream wstream = new(memStream); _bitmap?.Encode(wstream, SKEncodedImageFormat.Png, 100); }
/// <summary> /// Take a path provided by a user, draw it as a maptile. Potentially useful for exercise trackers. Resulting file must not be saved to the server as that would be user tracking. /// </summary> /// <param name="pointListAsString">a string of points separate by , and | </param> /// <returns>the png file with the path drawn over the mapdata in the area.</returns> public byte[] DrawUserPath(string pointListAsString) { //String is formatted as Lat,Lon~Lat,Lon~ repeating. Characters chosen to not be percent-encoded if submitted as part of the URL. //first, convert this to a list of latlon points string[] pointToConvert = pointListAsString.Split("|"); List <Coordinate> coords = pointToConvert.Select(p => new Coordinate(double.Parse(p.Split(',')[0]), double.Parse(p.Split(',')[1]))).ToList(); var mapBuffer = resolutionCell8 / 2; //Leave some area around the edges of where they went. GeoArea mapToDraw = new GeoArea(coords.Min(c => c.Y) - mapBuffer, coords.Min(c => c.X) - mapBuffer, coords.Max(c => c.Y) + mapBuffer, coords.Max(c => c.X) + mapBuffer); ImageStats info = new ImageStats(mapToDraw, 1024, 1024); LineString line = new LineString(coords.ToArray()); var drawableLine = PolygonToSKPoints(line, mapToDraw, info.degreesPerPixelX, info.degreesPerPixelY); //Now, draw that path on the map. var places = GetPlaces(mapToDraw); //, null, false, false, degreesPerPixelX * 4 ///TODO: restore item filtering var baseImage = DrawAreaAtSize(info, places); SKBitmap sKBitmap = SKBitmap.Decode(baseImage); SKCanvas canvas = new SKCanvas(sKBitmap); SKPaint paint = new SKPaint(); paint.Style = SKPaintStyle.Stroke; paint.StrokeWidth = 4; //Larger than normal lines at any zoom level. paint.Color = new SKColor(0, 0, 0); //Pure black, for maximum visibility. for (var x = 0; x < drawableLine.Length - 1; x++) { canvas.DrawLine(drawableLine[x], drawableLine[x + 1], paint); } var ms = new MemoryStream(); var skms = new SKManagedWStream(ms); sKBitmap.Encode(skms, SKEncodedImageFormat.Png, 100); var results = ms.ToArray(); skms.Dispose(); ms.Close(); ms.Dispose(); return(results); }
private Result GetImagePart(Mnemonic expression, IRuntime runtime) { if ( runtime.GetVariable("arrayOfBinaryData").Get(runtime) is String arrayImage && runtime.GetVariable("left").Get(runtime) is Number a && runtime.GetVariable("top").Get(runtime) is Number b && runtime.GetVariable("right").Get(runtime) is Number c && runtime.GetVariable("bottom").Get(runtime) is Number d ) { var binaryData = Convert.FromBase64String(arrayImage.Value); //arrayImage //.Select(e => e as Number) //.Select(n => n.ValueAsByte) //.ToArray(); var resourceBitmap = SKBitmap.Decode(binaryData); var bmp = new SKBitmap(); resourceBitmap.ExtractSubset(bmp, new SKRectI(a.ValueAsInt, b.ValueAsInt, c.ValueAsInt, d.ValueAsInt)); SKDynamicMemoryWStream ms = new SKDynamicMemoryWStream(); var data = bmp.Encode(SKEncodedImageFormat.Png, 100); var subimage = Convert.ToBase64String(data.ToArray()); //LoplaList loplaList = new LoplaList(); //foreach(var dbyte in data.ToArray()) //{ // loplaList.Add(new Number(dbyte)); //} //return new Result(loplaList); return(new Result(new String(subimage))); } return(new Result()); }
protected static Bitmap?GetBitmap(ImageSouce.ClipStream clipStream, int width = 0) { if (clipStream.Stream == null) { return(null); } TryReset(clipStream.Stream); using var ms = new MemoryStream(); clipStream.Stream.CopyTo(ms); TryReset(ms); using var bitmapSource = SKBitmap.Decode(ms); using var bitmapDest = new SKBitmap(bitmapSource.Width, bitmapSource.Height, SKColorType.Bgra8888, SKAlphaType.Unpremul); using var canvas = new SKCanvas(bitmapDest); var rect = clipStream.Circle ? new SKRect(0, 0, bitmapSource.Width, bitmapSource.Height) : new SKRect(clipStream.Left, clipStream.Top, clipStream.Right, clipStream.Bottom); var roundRect = clipStream.Circle ? new SKRoundRect(rect, bitmapSource.Width / 2f, bitmapSource.Height / 2f) : new SKRoundRect(rect, clipStream.Radius_X, clipStream.Radius_Y); canvas.ClipRoundRect(roundRect, antialias: true); canvas.DrawBitmap(bitmapSource, 0, 0); var stream = bitmapDest.Encode(SKEncodedImageFormat.Png, 100).AsStream(); TryReset(stream); //var tempFilePath = Path.Combine(IOPath.CacheDirectory, Path.GetFileName(Path.GetTempFileName() + ".png")); //using (var fs = File.Create(tempFilePath)) //{ // stream.CopyTo(fs); // TryReset(stream); //} return(GetDecodeBitmap(stream, width)); }
private RegisterIdentityViewModel CreateViewModelForRegister(bool photoUploadSucceeds) { SKBitmap bitmap = new SKBitmap(300, 300); string path = Path.Combine(Path.GetTempPath(), Folder); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } this.fullPath = Path.Combine(path, File); using (var data = bitmap.Encode(SKEncodedImageFormat.Jpeg, 100)) { byte[] bytes = data.ToArray(); using (FileStream fs = System.IO.File.OpenWrite(fullPath)) { fs.Write(bytes); } } this.neuronService.SetupGet(x => x.IsOnline).Returns(true); Guid guid = Guid.NewGuid(); // Upload attachment this.identity = new LegalIdentity { Id = guid.ToString(), State = IdentityState.Approved }; this.networkService.Setup(x => x.TryRequest(It.IsAny <Func <Task <LegalIdentity> > >(), It.IsAny <bool>(), It.IsAny <bool>(), It.IsAny <string>())) .Returns(Task.FromResult((photoUploadSucceeds, this.identity))); // Short circuit the begin invoke calls, so they're executed synchronously. this.dispatcher.Setup(x => x.BeginInvokeOnMainThread(It.IsAny <Action>())).Callback <Action>(x => x()); this.tagProfile.SetupGet(x => x.HttpFileUploadMaxSize).Returns(short.MaxValue); this.tagProfile.SetupGet(x => x.LegalJid).Returns(Guid.NewGuid().ToString); this.tagProfile.SetupGet(x => x.RegistryJid).Returns(Guid.NewGuid().ToString); this.tagProfile.SetupGet(x => x.ProvisioningJid).Returns(Guid.NewGuid().ToString); return(AViewModel()); }
private static void __DrawGfx() { var rotated = new SKBitmap(1024, 1024); var info = new SKRect(0, 0, 1024, 1024); using (SKCanvas canvas = new SKCanvas(rotated)) { using (SKPaint paint = new SKPaint { Style = SKPaintStyle.Stroke, Color = SKColors.Red, StrokeWidth = 25, IsAntialias = true }) { canvas.RotateDegrees(2); canvas.DrawCircle(info.Width / 2, info.Height / 2, 100, paint); paint.Style = SKPaintStyle.Fill; paint.Color = SKColors.Blue; canvas.DrawCircle(info.Width / 2, info.Height / 2, 75, paint); canvas.RotateDegrees(20); canvas.DrawCircle(info.Width / 2, info.Height / 2, 50, paint); paint.Style = SKPaintStyle.Fill; paint.Color = SKColors.Yellow; canvas.DrawCircle(info.Width / 2, info.Height / 2, 25, paint); paint.Color = SKColors.Red; canvas.ResetMatrix(); canvas.DrawOval(info.Width / 4, info.Height / 2, 25, 50, paint); } } using (var filstream = File.Open("xsj02_039_13_Gfx.png", FileMode.OpenOrCreate)) { rotated.Encode(filstream, SKEncodedImageFormat.Png, 1); } }
///<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); }
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation?orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat) { if (string.IsNullOrWhiteSpace(inputPath)) { throw new ArgumentNullException("inputPath"); } if (string.IsNullOrWhiteSpace(inputPath)) { throw new ArgumentNullException("outputPath"); } var skiaOutputFormat = GetImageFormat(selectedOutputFormat); var hasBackgroundColor = !string.IsNullOrWhiteSpace(options.BackgroundColor); var hasForegroundColor = !string.IsNullOrWhiteSpace(options.ForegroundLayer); var blur = options.Blur ?? 0; var hasIndicator = options.AddPlayedIndicator || options.UnplayedCount.HasValue || !options.PercentPlayed.Equals(0); using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace, autoOrient, orientation)) { if (bitmap == null) { throw new ArgumentOutOfRangeException(string.Format("Skia unable to read image {0}", inputPath)); } //_logger.Info("Color type {0}", bitmap.Info.ColorType); var originalImageSize = new ImageSize(bitmap.Width, bitmap.Height); if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize) && !autoOrient) { // Just spit out the original file if all the options are default return(inputPath); } var newImageSize = ImageHelper.GetNewImageSize(options, originalImageSize); var width = Convert.ToInt32(Math.Round(newImageSize.Width)); var height = Convert.ToInt32(Math.Round(newImageSize.Height)); using (var resizedBitmap = new SKBitmap(width, height))//, bitmap.ColorType, bitmap.AlphaType)) { // scale image var resizeMethod = SKBitmapResizeMethod.Lanczos3; bitmap.Resize(resizedBitmap, resizeMethod); // If all we're doing is resizing then we can stop now if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator) { _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath)); using (var outputStream = new SKFileWStream(outputPath)) { resizedBitmap.Encode(outputStream, skiaOutputFormat, quality); return(outputPath); } } // create bitmap to use for canvas drawing using (var saveBitmap = new SKBitmap(width, height))//, bitmap.ColorType, bitmap.AlphaType)) { // create canvas used to draw into bitmap using (var canvas = new SKCanvas(saveBitmap)) { // set background color if present if (hasBackgroundColor) { canvas.Clear(SKColor.Parse(options.BackgroundColor)); } // Add blur if option is present if (blur > 0) { using (var paint = new SKPaint()) { // create image from resized bitmap to apply blur using (var filter = SKImageFilter.CreateBlur(blur, blur)) { paint.ImageFilter = filter; canvas.DrawBitmap(resizedBitmap, SKRect.Create(width, height), paint); } } } else { // draw resized bitmap onto canvas canvas.DrawBitmap(resizedBitmap, SKRect.Create(width, height)); } // If foreground layer present then draw if (hasForegroundColor) { Double opacity; if (!Double.TryParse(options.ForegroundLayer, out opacity)) { opacity = .4; } canvas.DrawColor(new SKColor(0, 0, 0, (Byte)((1 - opacity) * 0xFF)), SKBlendMode.SrcOver); } if (hasIndicator) { DrawIndicator(canvas, width, height, options); } _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath)); using (var outputStream = new SKFileWStream(outputPath)) { saveBitmap.Encode(outputStream, skiaOutputFormat, quality); } } } } } return(outputPath); }
public void SaveImage(SKBitmap image, Stream stream) { image.Encode(stream, SKEncodedImageFormat.Jpeg, Quality); }
private async void ImageButton_Clicked_2(object sender, EventArgs e) { if (loading.Count == 0) { isRunning = true; string fileName = await DisplayPromptAsync("Save", "What would you like the file name to be?", "OK", "Cancel", "File Name"); //Gives option to save file with a custom name on photo gallery if (fileName != null && fileName != "" && fileName != "Cancel" && fileName != "OK") { option = await DisplayActionSheet("Quality", null, null, "Custom", "Max High", "Ultra High", "High", "Medium", "Low", "Very Low"); Option_Check(); cancel = false; canvasImage.IsVisible = true; canvasImageFast.IsVisible = false; loading.Add("Loading . . . "); double ri; double ci; double l; string downloadMacro; string downloadMicro; if (createAdvanced) { downloadMacro = macroInput; downloadMicro = microInput; ri = realInput; ci = complexInput; l = lengthInput; } else { downloadMacro = selectedColor; downloadMicro = selecterColorMicro; if (item <= integer - 1) { ri = varList1[item]; ci = varList2[item]; l = varList3[item]; } else { ri = SavedFractals[item - integer].SavedReal; ci = SavedFractals[item - integer].SavedComplex; l = SavedFractals[item - integer].SavedLength; } } double riCache = ri; double ciCache = ci; if (item >= 12 && item <= 15) { ri = 0.2; ci = 0; l = 1; } else if (item > integer - 1) { if (SavedFractals[item - integer].IsJuliaSet) { ri = 0.2; ci = 0; l = 1; } } else { julia = -1; } //Making 2x2 array with size height export and width export Complex complix; Pixel[,] picture = new Pixel[heightExport, widthExport]; int a; int b; //Setting format to Jpeg SKEncodedImageFormat imageFormat = SKEncodedImageFormat.Jpeg; int quality = 100; //For loop with calculations, every column calulated between loading changes //i goes up by the length value to make proportional for (double i = ri * heightExport; i < (ri + l) * heightExport; i += l) { if (cancel) { break; } Loading(); for (double j = ci * widthExport; j < (ci + l) * widthExport; j += l) { if (cancel) { break; } //setting shift of and position a = (int)((i - ri * heightExport) / l); b = (int)((j - ci * widthExport) / l); complix = new Complex((i - (14 * heightExport / 20.0)) / (widthExport / 3.0), (j - (widthExport / 2.0)) / (heightExport / 3.0 * widthExport / heightExport)); int onoff = (int)(Iterate(complix, item, riCache, ciCache) * 255); updatePixelInputs(downloadMacro, downloadMicro, onoff); picture[a, b] = new Pixel(intInput1, intInput2, intInput3); //Sets individual pixels if (picture[a, b] == null) { picture[a, b] = new Pixel(0, 0, 0); SKColor colorPixelNull = new SKColor((byte)picture[a, b].GetRed(), (byte)picture[a, b].GetGreen(), (byte)picture[a, b].GetBlue()); bitmap.SetPixel(a, b, colorPixelNull); } else { SKColor colorPixel = new SKColor((byte)picture[a, b].GetRed(), (byte)picture[a, b].GetGreen(), (byte)picture[a, b].GetBlue()); bitmap.SetPixel(a, b, colorPixel); } } //Saves image every column using (MemoryStream memStream = new MemoryStream()) using (SKManagedWStream wstream = new SKManagedWStream(memStream)) { bitmap.Encode(wstream, imageFormat, quality); byte[] data = memStream.ToArray(); if (data != null && data.Length != 0) { await DependencyService.Get <IPhotoLibrary>(). SavePhotoAsync(data, "SaveFileFormats", fileName + ".Jpeg"); } } } cancel = false; } heightExport = (int)(Settings.QualityOptions[0].Quality); widthExport = (int)(Settings.QualityOptions[0].Quality); if (loading.Count != 0) { loading.RemoveAt(0); } isRunning = false; } }
/// <summary> /// Export image to stream. /// </summary> /// <param name="stream">Stream to export the image to..</param> /// <param name="format">Format for the encoding.</param> /// <returns>Byte array.</returns> public void ExportToStream(Stream stream, Format format) { bitmap.Encode(stream, format.ToSkiaFormat(), 100); }
void Save(string destination, SKBitmap tempBitmap) { using var stream = File.Create(destination); tempBitmap.Encode(stream, SKEncodedImageFormat.Png, 100); }
/// <inheritdoc cref="ToPng(QrCode, int, int)"/> /// <param name="background">The background color.</param> /// <param name="foreground">The foreground color.</param> public static byte[] ToPng(this QrCode qrCode, int scale, int border, SKColor foreground, SKColor background) { using SKBitmap bitmap = qrCode.ToBitmap(scale, border, foreground, background); using SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 90); return(data.ToArray()); }
public byte[] DrawAreaAtSize(ImageStats stats, List <CompletePaintOp> paintOps) { //This is the new core drawing function. Once the paint operations have been created, I just draw them here. //baseline image data stuff SKBitmap bitmap = new SKBitmap(stats.imageSizeX, stats.imageSizeY, SKColorType.Rgba8888, SKAlphaType.Premul); SKCanvas canvas = new SKCanvas(bitmap); canvas.Clear(eraser.Color); canvas.Scale(1, -1, stats.imageSizeX / 2, stats.imageSizeY / 2); SKPaint paint = new SKPaint(); foreach (var w in paintOps.OrderByDescending(p => p.paintOp.LayerId).ThenByDescending(p => p.areaSize)) { paint = cachedPaints[w.paintOp.Id]; //SetPaintForTPP(w.paintOp); // w.paintOp.paint; if (w.paintOp.FromTag) //FromTag is for when you are saving color data directly to each element, instead of tying it to a styleset. { paint.Color = SKColor.Parse(w.tagValue); } if (w.paintOp.Randomize) //To randomize the color on every Draw call. { paint.Color = new SKColor((byte)r.Next(0, 255), (byte)r.Next(0, 255), (byte)r.Next(0, 255), 99); } paint.StrokeWidth = (float)w.lineWidthPixels; var path = new SKPath(); switch (w.elementGeometry.GeometryType) { case "Polygon": var p = w.elementGeometry as Polygon; //if (p.Envelope.Length < (stats.degreesPerPixelX * 4)) //This poly's perimeter is too small to draw //continue; path.AddPoly(PolygonToSKPoints(p.ExteriorRing, stats.area, stats.degreesPerPixelX, stats.degreesPerPixelY)); foreach (var ir in p.Holes) { //if (ir.Envelope.Length < (w.lineWidth * 4)) //This poly's perimeter is less than 2x2 pixels in size. //continue; path.AddPoly(PolygonToSKPoints(ir, stats.area, stats.degreesPerPixelX, stats.degreesPerPixelY)); } canvas.DrawPath(path, paint); break; case "MultiPolygon": foreach (var p2 in ((MultiPolygon)w.elementGeometry).Geometries) { //if (p2.Envelope.Length < (stats.degreesPerPixelX * 4)) //This poly's perimeter is too small to draw //continue; var p2p = p2 as Polygon; path.AddPoly(PolygonToSKPoints(p2p.ExteriorRing, stats.area, stats.degreesPerPixelX, stats.degreesPerPixelY)); foreach (var ir in p2p.Holes) { //if (ir.Envelope.Length < (stats.degreesPerPixelX * 4)) //This poly's perimeter is too small to draw // continue; path.AddPoly(PolygonToSKPoints(ir, stats.area, stats.degreesPerPixelX, stats.degreesPerPixelY)); } canvas.DrawPath(path, paint); } break; case "LineString": var firstPoint = w.elementGeometry.Coordinates.First(); var lastPoint = w.elementGeometry.Coordinates.Last(); var points = PolygonToSKPoints(w.elementGeometry, stats.area, stats.degreesPerPixelX, stats.degreesPerPixelY); if (firstPoint.Equals(lastPoint)) { //This is a closed shape. Check to see if it's supposed to be filled in. if (paint.Style == SKPaintStyle.Fill) { path.AddPoly(points); canvas.DrawPath(path, paint); continue; } } //if (w.lineWidth < 1) //Don't draw lines we can't see. //continue; for (var line = 0; line < points.Length - 1; line++) { canvas.DrawLine(points[line], points[line + 1], paint); } break; case "MultiLineString": //if (w.lineWidth < 1) //Don't draw lines we can't see. //continue; foreach (var p3 in ((MultiLineString)w.elementGeometry).Geometries) { var points2 = PolygonToSKPoints(p3, stats.area, stats.degreesPerPixelX, stats.degreesPerPixelY); for (var line = 0; line < points2.Length - 1; line++) { canvas.DrawLine(points2[line], points2[line + 1], paint); } } break; case "Point": var convertedPoint = PolygonToSKPoints(w.elementGeometry, stats.area, stats.degreesPerPixelX, stats.degreesPerPixelY); //If this type has an icon, use it. Otherwise draw a circle in that type's color. if (!string.IsNullOrEmpty(w.paintOp.FileName)) { SKBitmap icon = SKBitmap.Decode(TagParser.cachedBitmaps[w.paintOp.FileName]); //TODO optimize by making icons in Initialize. canvas.DrawBitmap(icon, convertedPoint[0]); } else { var circleRadius = (float)(ConstantValues.resolutionCell10 / stats.degreesPerPixelX / 2); //I want points to be drawn as 1 Cell10 in diameter. canvas.DrawCircle(convertedPoint[0], circleRadius, paint); //TODO re-add outline paint to this DLL not TagParser. //canvas.DrawCircle(convertedPoint[0], circleRadius, TagParser.outlinePaint); } break; default: Log.WriteLog("Unknown geometry type found, not drawn."); break; } } //} var ms = new MemoryStream(); var skms = new SKManagedWStream(ms); bitmap.Encode(skms, SKEncodedImageFormat.Png, 100); var results = ms.ToArray(); skms.Dispose(); ms.Close(); ms.Dispose(); return(results); }
async void OnCanvasViewTapped(object sender, EventArgs e) { List <string> scenes = new List <string>(); string action = await DisplayActionSheet("What to do?", null, null, "Load Scene", "Save Scene", "Delete Scene", "Render Scene"); if (action == "Load Scene") { var sceneDescs = db.Table <SceneDescription>(); foreach (var item in sceneDescs) { scenes.Add(item.sceneName); } string whatToLoad = await DisplayActionSheet("Which scene to load?", null, null, scenes.ToArray()); if (whatToLoad != null) { sc.LoadScene(whatToLoad); sc.SetMainCamera(GetCameraFromEntry()); LoadShapesIntoOC(); LoadLightsIntoOC(); } } else if (action == "Save Scene") { string sceneName = await DisplayPromptAsync("Save Scene", "Scene name:"); sc.SaveScene(sceneName); } else if (action == "Delete Scene") { var sceneDescs = db.Table <SceneDescription>(); foreach (var item in sceneDescs) { scenes.Add(item.sceneName); } string whatToDelete = await DisplayActionSheet("Which scene to load?", null, null, scenes.ToArray()); if (whatToDelete != null) { sc.DeleteScene(whatToDelete); } } else if (action == "Render Scene") { bigImage = new SKBitmap(1024, 1024); sc.mainCamera.finishedRendering = false; sc.mainCamera.Render(bigImage); Toast.MakeText(Android.App.Application.Context, "Rendering, please wait! (it may take a loooong time)", ToastLength.Long).Show(); while (!sc.mainCamera.finishedRendering) { Console.WriteLine("still busy"); await Task.Delay(25); } try { using (MemoryStream ms = new MemoryStream()) { using (SKManagedWStream wstream = new SKManagedWStream(ms)) { bigImage.Encode(wstream, SKEncodedImageFormat.Png, 100); byte[] data = ms.ToArray(); var status = await CrossPermissions.Current.CheckPermissionStatusAsync <StoragePermission>(); if (status != Plugin.Permissions.Abstractions.PermissionStatus.Granted) { await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Plugin.Permissions.Abstractions.Permission.Storage); status = await CrossPermissions.Current.RequestPermissionAsync <StoragePermission>(); } if (status == Plugin.Permissions.Abstractions.PermissionStatus.Granted) { string filename = DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".png"; if (!Directory.Exists(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/DCIM/xTracer")) { Directory.CreateDirectory(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/DCIM/xTracer"); } if (File.Exists(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/DCIM/xTracer/" + filename)) { File.Delete(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/DCIM/xTracer/" + filename); } using (var stream = File.Create(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/DCIM/xTracer/" + filename)) { stream.Write(data, 0, data.Length); Toast.MakeText(Android.App.Application.Context, "Finished rendering!, saved to " + Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/DCIM/xTracer/" + filename, ToastLength.Long).Show(); } } } } } catch (Exception) { throw; } } }
/// <summary> /// 内部使用 /// </summary> private async Task <ISharedImageMessage> InternalUploadPictureAsync(InternalSessionInfo session, UploadTarget type, Stream imgStream, bool disposeStream, CancellationToken token = default) { // 使用 disposeStream 目的是不使上层 caller 创建多余的状态机 if (session.ApiVersion <= new Version(1, 7, 0)) { Guid guid = Guid.NewGuid(); MemoryStream ms = new MemoryStream(8192); // 无论如何都做一份copy await imgStream.CopyToAsync(ms, 81920, token).ConfigureAwait(false); ImageHttpListener.RegisterImage(guid, ms); return(new ImageMessage(null, $"http://127.0.0.1:{ImageHttpListener.Port}/fetch?guid={guid:n}", null)); } Stream?internalStream = null; bool internalCreated = false; long pervious = 0; if (!imgStream.CanSeek || imgStream.CanTimeout) // 对于 CanTimeOut 的 imgStream, 或者无法Seek的, 一律假定其读取行为是阻塞的 // 为其创建一个内部缓存先行异步读取 { internalStream = new MemoryStream(8192); internalCreated = true; await imgStream.CopyToAsync(internalStream, 81920, token); internalStream.Seek(0, SeekOrigin.Begin); } else // 否则不创建副本, 避免多余的堆分配 { internalStream = imgStream; pervious = imgStream.Position; } HttpContent sessionKeyContent = new StringContent(session.SessionKey); sessionKeyContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "sessionKey" }; HttpContent typeContent = new StringContent(type.ToString().ToLower()); typeContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "type" }; string format; using SKManagedStream skstream = new SKManagedStream(internalStream, false); using (SKCodec codec = SKCodec.Create(skstream)) // 已经把数据读到非托管内存里边了, 就不用管input的死活了 { var skformat = codec.EncodedFormat; format = skformat.ToString().ToLower(); switch (skformat) { case SKEncodedImageFormat.Gif: case SKEncodedImageFormat.Jpeg: case SKEncodedImageFormat.Png: break; default: { skstream.Seek(0); using (SKBitmap bitmap = SKBitmap.Decode(skstream)) { if (!internalCreated) { internalStream = new MemoryStream(8192); internalCreated = true; } else { internalStream.Seek(0, SeekOrigin.Begin); } bitmap.Encode(internalStream, SKEncodedImageFormat.Png, 100); } format = "png"; break; } } } if (internalCreated) { internalStream.Seek(0, SeekOrigin.Begin); } else // internalStream == imgStream { internalStream.Seek(pervious - internalStream.Position, SeekOrigin.Current); } HttpContent imageContent = new StreamContent(internalStream); imageContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "img", FileName = $"{Guid.NewGuid():n}.{format}" }; imageContent.Headers.ContentType = new MediaTypeHeaderValue("image/" + format); HttpContent[] contents = new HttpContent[] { sessionKeyContent, typeContent, imageContent }; try { CreateLinkedUserSessionToken(session.Token, token, out CancellationTokenSource? cts, out token); return(await _client.PostAsync($"{_options.BaseUrl}/uploadImage", contents, token) .AsApiRespAsync <ISharedImageMessage, ImageMessage>(token) .DisposeWhenCompleted(cts) .ContinueWith(t => t.IsFaulted && t.Exception !.InnerException is JsonException ? throw new NotSupportedException("当前版本的mirai-api-http无法发送图片。") : t, TaskContinuationOptions.ExecuteSynchronously).Unwrap().ConfigureAwait(false)); // ^-- 处理 JsonException 到 NotSupportedException, https://github.com/mamoe/mirai-api-http/issues/85 // internalStream 是 MemoryStream, 内部为全托管字段不需要 Dispose } finally { if (disposeStream) { imgStream.Dispose(); } } }
/// <summary> /// 内部使用 /// </summary> /// <exception cref="InvalidOperationException"/> /// <param name="type">目标类型</param> /// <param name="imgStream">图片流</param> /// <remarks> /// 注意: 当 mirai-api-http 的版本小于等于v1.7.0时, 本方法返回的将是一个只有 Url 有值的 <see cref="ImageMessage"/> /// </remarks> /// <returns>一个 <see cref="ImageMessage"/> 实例, 可用于以后的消息发送</returns> private static Task <ImageMessage> InternalUploadPictureAsync(InternalSessionInfo session, UploadTarget type, Stream imgStream) { if (session.ApiVersion <= new Version(1, 7, 0)) { Guid guid = Guid.NewGuid(); ImageHttpListener.RegisterImage(guid, imgStream); return(Task.FromResult(new ImageMessage(null, $"http://127.0.0.1:{ImageHttpListener.Port}/fetch?guid={guid:n}", null))); } HttpContent sessionKeyContent = new StringContent(session.SessionKey); sessionKeyContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "sessionKey" }; HttpContent typeContent = new StringContent(type.ToString().ToLower()); typeContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "type" }; string format; using MemoryStream codecMemoryStream = new MemoryStream(); imgStream.CopyTo(codecMemoryStream); codecMemoryStream.Seek(0, SeekOrigin.Begin); using (SKCodec codec = SKCodec.Create(codecMemoryStream)) { var skformat = codec.EncodedFormat; format = skformat.ToString().ToLower(); switch (skformat) { case SKEncodedImageFormat.Gif: case SKEncodedImageFormat.Jpeg: case SKEncodedImageFormat.Png: break; default: imgStream.Seek(0, SeekOrigin.Begin); using (SKBitmap bitmap = SKBitmap.Decode(imgStream)) { MemoryStream ms = new MemoryStream(); bitmap.Encode(ms, SKEncodedImageFormat.Png, 100); imgStream = ms; format = SKEncodedImageFormat.Png.ToString().ToLower(); } break; } } imgStream.Seek(0, SeekOrigin.Begin); HttpContent imageContent = new StreamContent(imgStream); imageContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "img", FileName = $"{Guid.NewGuid():n}.{format}" }; imageContent.Headers.ContentType = new MediaTypeHeaderValue("image/" + format); HttpContent[] contents = new HttpContent[] { sessionKeyContent, typeContent, imageContent }; return(session.Client.PostAsync($"{session.Options.BaseUrl}/uploadImage", contents, session.Token) .AsNoSuccCodeApiRespAsync <ImageMessage>(session.Token) .ContinueWith(t => t.IsFaulted && t.Exception !.InnerException is JsonException ? throw new NotSupportedException("当前版本的mirai-api-http无法发送图片。") : t, TaskContinuationOptions.ExecuteSynchronously).Unwrap()); // ^-- 处理 JsonException 到 NotSupportedException, https://github.com/mamoe/mirai-api-http/issues/85 }
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)); }
public ResizedImageInfo Resize(DpiPath dpi, string destination, Func <Stream> getStream = null) { var sw = new Stopwatch(); sw.Start(); var(bgScaledSize, bgScale) = backgroundTools.GetScaledSize(backgroundOriginalSize, dpi); // Make the canvas size match the desired size var canvasSize = bgScaledSize; if (dpi.Size is SKSize size && size.Width != size.Height) { var scale = (float)dpi.Scale; canvasSize = new SKSizeI((int)(size.Width * scale), (int)(size.Height * scale)); } // Allocate using (var tempBitmap = new SKBitmap(canvasSize.Width, canvasSize.Height)) { // Draw (copy) using (var canvas = new SKCanvas(tempBitmap)) { canvas.Clear(Info.Color ?? SKColors.Transparent); canvas.Save(); canvas.Translate( (canvasSize.Width - bgScaledSize.Width) / 2, (canvasSize.Height - bgScaledSize.Height) / 2); canvas.Scale(bgScale, bgScale); backgroundTools.DrawUnscaled(canvas, bgScale); canvas.Restore(); if (hasForeground) { var userFgScale = (float)Info.ForegroundScale; // get the ratio to make the foreground fill the background var fitRatio = bgScaledSize.Width / foregroundOriginalSize.Width; // calculate the scale for the foreground to fit the background exactly var(fgScaledSize, fgScale) = foregroundTools.GetScaledSize(foregroundOriginalSize, (decimal)fitRatio); //Logger.Log("\tdpi.Size: " + dpi.Size); //Logger.Log("\tdpi.Scale: " + dpi.Scale); //Logger.Log("\tbgScaledSize: " + bgScaledSize); //Logger.Log("\tbgScale: " + bgScale); //Logger.Log("\tforegroundOriginalSize: " + foregroundOriginalSize); //Logger.Log("\tfgScaledSize: " + fgScaledSize); //Logger.Log("\tfgScale: " + fgScale); //Logger.Log("\tuserFgScale: " + userFgScale); // now work out the center as if the canvas was exactly the same size as the foreground var fgScaledSizeCenterX = foregroundOriginalSize.Width / 2; var fgScaledSizeCenterY = foregroundOriginalSize.Height / 2; //Logger.Log("\tfgScaledSizeCenterX: " + fgScaledSizeCenterX); //Logger.Log("\tfgScaledSizeCenterY: " + fgScaledSizeCenterY); // center the foreground canvas.Translate( (canvasSize.Width - fgScaledSize.Width) / 2, (canvasSize.Height - fgScaledSize.Height) / 2); // scale so the forground is the same size as the background canvas.Scale(fgScale, fgScale); // scale to the user scale, centering canvas.Scale(userFgScale, userFgScale, fgScaledSizeCenterX, fgScaledSizeCenterY); foregroundTools.DrawUnscaled(canvas, fgScale * userFgScale); } } // Save (encode) if (getStream is not null) { var stream = getStream(); tempBitmap.Encode(stream, SKEncodedImageFormat.Png, 100); } else { using var wrapper = File.Create(destination); tempBitmap.Encode(wrapper, SKEncodedImageFormat.Png, 100); } } sw.Stop(); Logger?.Log($"Save app icon took {sw.ElapsedMilliseconds}ms ({destination})"); return(new ResizedImageInfo { Dpi = dpi, Filename = destination }); }
public async void GenerateMandelbrotZoom(double ri, double ci, double l, string macroColor, string microColor, int index) { double riCache = ri; double ciCache = ci; if (index >= 12 && index <= 15) { ri = 0.2; ci = 0; l = 1; } else if (index > integer - 1) { if (SavedFractals[item - integer].IsJuliaSet) { ri = 0.2; ci = 0; l = 1; } } else if (index == -2) { ri = 0.2; ci = 0; l = 1; } else { julia = -1; } if (loading.Count == 0) { isRunning = true; cancel = false; canvasImage.IsVisible = false; loading.Add("Loading . . . "); bitmapFast = new SKBitmap(widthExport, heightExport, true); canvasImageFast.IsVisible = true; cancel = false; //Making 2x2 array with size height export and width export Complex complix; Pixel[,] picture = new Pixel[widthExport, heightExport]; int a; int b; //Setting format to Jpeg SKEncodedImageFormat imageFormat = SKEncodedImageFormat.Jpeg; int quality = 100; //For loop with calculations, every column calulated between loading changes //i goes up by the length value to make proportional for (double i = ri * widthExport; i < (ri + l) * widthExport; i += l) { if (cancel) { break; } for (double j = ci * heightExport; j < (ci + l) * heightExport; j += l) { if (cancel) { break; } //setting shift of and position a = (int)((i - ri * widthExport) / l); b = (int)((j - ci * heightExport) / l); complix = new Complex((i - (14 * heightExport / 20.0)) / (widthExport / 3.0), (j - (widthExport / 2.0)) / (heightExport / 3.0 * widthExport / heightExport)); int onoff = (int)(Iterate(complix, index, riCache, ciCache) * 255); updatePixelInputs(macroColor, microColor, onoff); picture[a, b] = new Pixel(intInput1, intInput2, intInput3); //Sets individual pixels if (picture[a, b] == null) { picture[a, b] = new Pixel(0, 0, 0); SKColor colorPixelNull = new SKColor((byte)picture[a, b].GetRed(), (byte)picture[a, b].GetGreen(), (byte)picture[a, b].GetBlue()); bitmapFast.SetPixel(a, b, colorPixelNull); } else { SKColor colorPixel = new SKColor((byte)picture[a, b].GetRed(), (byte)picture[a, b].GetGreen(), (byte)picture[a, b].GetBlue()); bitmapFast.SetPixel(a, b, colorPixel); } } //Saves image every column using (MemoryStream memStream = new MemoryStream()) using (SKManagedWStream wstream = new SKManagedWStream(memStream)) { bitmapFast.Encode(wstream, imageFormat, quality); byte[] data = memStream.ToArray(); if (data != null && data.Length != 0) { string fileName = null; await DependencyService.Get <IPhotoLibrary>(). SavePhotoAsync(data, "SaveFileFormats", fileName + ".Jpeg"); } } Loading(); } loading.RemoveAt(0); isRunning = false; } }
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)); }
public void SaveImage(SKBitmap image, Stream stream) { image.Encode(stream, SKEncodedImageFormat.Gif, 85); }
static void save(SKBitmap image, string file) { using var stream = File.OpenWrite(file); image.Encode(stream, SKEncodedImageFormat.Png, 9); }
private static void SaveImage(string filename, SKBitmap bitmap) { using var stream = File.OpenWrite(filename); bitmap.Encode(stream, SKEncodedImageFormat.Png, 0); }
private async Task DrawPreview() { AddButton.IsEnabled = false; UpButton.IsEnabled = false; DownButton.IsEnabled = false; DeleteButton.IsEnabled = false; ClearButton.IsEnabled = false; SizeSlider.IsEnabled = false; OpenImageButton.IsEnabled = false; SaveImageButton.IsEnabled = false; var margin = UserSettings.Default.ImageMergerMargin; int num = 1, curW = 0, curH = 0, maxWidth = 0, maxHeight = 0, lineMaxHeight = 0, imagesPerRow = Convert.ToInt32(SizeSlider.Value); var positions = new Dictionary <int, SKPoint>(); var images = new SKBitmap[ImagesListBox.Items.Count]; for (var i = 0; i < images.Length; i++) { var item = (ListBoxItem)ImagesListBox.Items[i]; var ms = new MemoryStream(); var stream = new FileStream(item.ContentStringFormat, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); if (item.ContentStringFormat.EndsWith(".tif")) { await using var tmp = new MemoryStream(); await stream.CopyToAsync(tmp); System.Drawing.Image.FromStream(tmp).Save(ms, ImageFormat.Png); } else { await stream.CopyToAsync(ms); } var image = SKBitmap.Decode(ms.ToArray()); positions[i] = new SKPoint(curW, curH); images[i] = image; if (image.Height > lineMaxHeight) { lineMaxHeight = image.Height; } if (num % imagesPerRow == 0) { maxWidth = curW + image.Width + margin; curH += lineMaxHeight + margin; curW = 0; lineMaxHeight = 0; } else { maxHeight = curH + lineMaxHeight + margin; curW += image.Width + margin; if (curW > maxWidth) { maxWidth = curW; } } num++; } await Task.Run(() => { using var bmp = new SKBitmap(maxWidth - margin, maxHeight - margin, SKColorType.Rgba8888, SKAlphaType.Premul); using var canvas = new SKCanvas(bmp); for (var i = 0; i < images.Length; i++) { using (images[i]) { canvas.DrawBitmap(images[i], positions[i], new SKPaint { FilterQuality = SKFilterQuality.High, IsAntialias = true }); } } using var data = bmp.Encode(SKEncodedImageFormat.Png, 100); using var stream = new MemoryStream(_imagebuffer = data.ToArray()); var photo = new BitmapImage(); photo.BeginInit(); photo.CacheOption = BitmapCacheOption.OnLoad; photo.StreamSource = stream; photo.EndInit(); photo.Freeze(); Application.Current.Dispatcher.Invoke(delegate { ImagePreview.Source = photo; }); }).ContinueWith(t => { AddButton.IsEnabled = true; UpButton.IsEnabled = true; DownButton.IsEnabled = true; DeleteButton.IsEnabled = true; ClearButton.IsEnabled = true; SizeSlider.IsEnabled = true; OpenImageButton.IsEnabled = true; SaveImageButton.IsEnabled = true; }, TaskScheduler.FromCurrentSynchronizationContext()); }