public async UnaryResult <Nil> ReportScreenshot(Bgra32Image screenshot, DateTimeOffset timestamp) { using (screenshot) { if (this.IsScreenshotEnabled) { var workerId = await this.WorkerInitializeAsync().ConfigureAwait(false); await this.RetryWhenLocked(() => { this.Connection.InsertOrReplace(new WorkerScreenshot() { WorkerId = workerId, Width = screenshot.Width, Height = screenshot.Height, Data = screenshot.Data.ToArray(), TimestampOnWorker = timestamp, TimestampOnServer = DateTimeOffset.Now, }); }).ConfigureAwait(false); } } return(Nil.Default); }
private async Task UpdateScreen() { var source = this.imgScreen.Source as WriteableBitmap; var img = await this._connection.CaptureContentAsync(); this._screenImage?.Dispose(); this._screenImage = img; var createNewBitmap = source == null || source.PixelWidth != img.Width || source.PixelHeight != img.Height; if (createNewBitmap) { source = new WriteableBitmap(img.Width, img.Height, 96, 96, PixelFormats.Bgr32, null); } source.Lock(); try { CopyPixels(img, source.BackBuffer, source.BackBufferStride * source.PixelHeight); source.AddDirtyRect(new Int32Rect(0, 0, source.PixelWidth, source.PixelHeight)); } finally { source.Unlock(); } this.BindingModel.GameWidth = img.Width; this.BindingModel.GameHeight = img.Height; if (createNewBitmap) { this.imgScreen.Source = source; } }
public static Bgra32Image CreateDiff(Bgra32Image a, Bgra32Image b, int tolerance) { Debug.Assert(a.W == b.W && a.H == b.H); var diff = new Bgra32Image(null, a.W, a.H); diff.RefreshDiffAsync(a, b, tolerance); return(diff); }
public Bgr2432InputImage(Bgra32Image image) { this._image = image; var data = image.Data; this._data = data.Array; this._offset = data.Offset; }
private async Task UpdateCursorImage() { if (this._connection == null) { return; } try { var source = this.imgCursor.Source as WriteableBitmap; bool createNewBitmap; var img = await this._connection.GetCursorImageAsync(); this._cursorImage?.Dispose(); this._cursorImage = img; createNewBitmap = source == null || source.PixelWidth != img.Width || source.PixelHeight != img.Height; if (createNewBitmap) { source = new WriteableBitmap(img.Width, img.Height, 96, 96, PixelFormats.Pbgra32, null); } source.Lock(); try { CopyPixels(img, source.BackBuffer, source.BackBufferStride * source.PixelHeight); source.AddDirtyRect(new Int32Rect(0, 0, source.PixelWidth, source.PixelHeight)); } finally { source.Unlock(); } if (createNewBitmap) { this.imgCursor.Source = source; } } catch (Exception ex) { if (Debugger.IsAttached) { Debugger.Break(); } this._connection = null; MessageBox.Show(this, ex.ToString(), "エラー", MessageBoxButton.OK, MessageBoxImage.Error); } }
public bool IsMatch(Bgra32Image cursorImage) { if (cursorImage.Width != ExpectedSize || cursorImage.Height != ExpectedSize) { return(false); } var pixels = MemoryMarshal.Cast <byte, uint>((ReadOnlySpan <byte>)cursorImage.Data); for (var y = 0; y < ExpectedSize; y++) { uint lineBitmap = 0; uint lineMask = 0; for (var x = 0; x < ExpectedSize; x++) { var pixel = pixels[y * ExpectedSize + x]; // Alpha が 0 ならば透明と判断 var isTransparent = (pixel & 0xff000000) == 0; if (!isTransparent) { lineMask |= 0b1000_0000_0000_0000u >> x; // 真っ白でなければ色がついていると判断 var isColored = (pixel & 0x00ffffff) != 0x00ffffff; if (isColored) { lineBitmap |= 0b1000_0000_0000_0000u >> x; } } } uint expectedMask = this.Mask[y]; if (lineMask != expectedMask) { return(false); } if (lineBitmap != (this.Bitmap[y] & expectedMask)) { return(false); } } return(true); }
public void SetImages(BitmapSource left, BitmapSource right, int tolerance) { // check tolerance if (tolerance < 0 || tolerance > 255) { ErrorLogLine("Tolerance must be integer from 0 to 255"); return; } // Load images int w = Math.Max(left.PixelWidth, right.PixelWidth); int h = Math.Max(left.PixelHeight, right.PixelHeight); var image1 = GetImage2D(left, w, h); var image2 = GetImage2D(right, w, h); var imaged = new Bgra32Image(null, w, h); if (null == image1 || null == image2) { return; } // done this.leftImage = image1; this.rightImage = image2; if (null != this.diffImage) { this.diffImage.GenDiffComplete -= DiffImage_GenDiffComplete; } this.diffImage = new Bgra32Image(null, w, h); if (null != this.diffImage) { this.diffImage.GenDiffComplete += DiffImage_GenDiffComplete; } this.leftThumbnail.Source = this.leftImage.ImageSource; this.rightThumbnail.Source = this.rightImage.ImageSource; this.diffThumbnail.Source = this.diffImage.ImageSource; SwitchMainImage(MainImageType.DIFF); RefreshDiffImage(tolerance); }
/// <summary> /// スクリーンショットを送信します。 /// </summary> public abstract Task ReportScreenshotAsync(Bgra32Image screenshot, DateTimeOffset timestamp);
public void RefreshDiffAsync(Bgra32Image a, Bgra32Image b, int tolerance) { // do some basic check Debug.Assert(a.W == b.W && a.H == b.H); Debug.Assert(a.W == this.W && a.H == this.H); if (tolerance < 0) { tolerance = 0; } if (tolerance > 255) { tolerance = 255; } #if true uint numCpuCores = 8; // TODO: get actual number of cores/processors Debug.Assert(this.ImageSource is WriteableBitmap); var bmp = this.ImageSource as WriteableBitmap; bmp.Lock(); long stride = bmp.BackBufferStride; bool strideEqualsWidth = (this.W * 4 == stride); long buffer = (long)bmp.BackBuffer; Parallel.For(0, numCpuCores, core => { long start = a.Pixels.Length * core / numCpuCores; long end = a.Pixels.Length * (core + 1) / numCpuCores; for (long i = start; i < end; ++i) { uint actualDiff, diffColor; GetDiff(out actualDiff, out diffColor, a.Pixels[i], b.Pixels[i], tolerance); this.Pixels[i] = actualDiff; if (strideEqualsWidth) { unsafe { ((uint *)buffer)[i] = diffColor; } } else { long x = i % this.W; long y = i / this.W; long ptr = buffer + y * stride + x * 4; unsafe { *(uint *)ptr = diffColor; } } } }); bmp.AddDirtyRect(new Int32Rect(0, 0, this.W, this.H)); bmp.Unlock(); this.GenDiffComplete(this, tolerance); #else // create a new diff task Task task = null; task = new Task((object state) => { uint[] diff = new uint[this.Pixels.Length]; uint[] color = new uint[this.Pixels.Length]; int taskTolerance = (int)state; uint numCpuCores = 8; // TODO: get actual number of core Parallel.For(0, numCpuCores, core => { long start = a.Pixels.Length * core / numCpuCores; long end = a.Pixels.Length * (core + 1) / numCpuCores; for (long i = start; i < end; ++i) { if (task != this.genDiffTask) { return; } uint actualDiff, diffColor; GetDiff(out actualDiff, out diffColor, a.Pixels[i], b.Pixels[i], taskTolerance); diff[i] = actualDiff; color[i] = diffColor; } }); Application.Current.Dispatcher.BeginInvoke((Action)(() => { if (this.genDiffTask == task) { // Update member variables, trigger events, when the task is done. this.Pixels = diff; Debug.Assert(this.ImageSource is WriteableBitmap); (this.ImageSource as WriteableBitmap).WritePixels(new Int32Rect(0, 0, this.W, this.H), color, this.W * 4, 0); this.GenDiffComplete(this, taskTolerance); } })); }, tolerance); this.genDiffTask = task; task.Start(); #endif }
public override Task ReportScreenshotAsync(Bgra32Image screenshot, DateTimeOffset timestamp) => this._service.ReportScreenshot(screenshot, timestamp).ResponseAsync;
public override Task ReportScreenshotAsync(Bgra32Image screenshot, DateTimeOffset timestamp) { return(Task.CompletedTask); }
private static unsafe void CopyPixels(Bgra32Image image, IntPtr dest, int destLength) { ((Span <byte>)image.Data).CopyTo(new Span <byte>((void *)dest, destLength)); }