public static void CopyTo(this ANDROIDIMAGE src, ref MemoryBitmap <System.Numerics.Vector3> dst) { if (dst.Width != src.Width || dst.Height != src.Height) { dst = default; } if (dst.IsEmpty) { dst = new MemoryBitmap <System.Numerics.Vector3>(src.Width, src.Height, Pixel.BGR96F.Format); } src._CopyYuv445345To(dst.AsSpanBitmap()); }
public void OnImageAvailable(Android.Media.ImageReader imageReader) { Android.Media.Image image = null; Android.Graphics.Bitmap bitmapFromPlane0 = null; Android.Graphics.Bitmap bitmapToSave = null; try { image = imageReader.AcquireLatestImage(); if (image != null) { Android.Media.Image.Plane[] planes = image.GetPlanes(); if (planes.Length > 0) { int rowPadding = planes[0].RowStride - planes[0].PixelStride * mWidth; bitmapFromPlane0 = Android.Graphics.Bitmap.CreateBitmap ( width: (mWidth + rowPadding / planes[0].PixelStride), // 此处不能直接采用 Width, 否则保存的图片会出现花屏 height: mHeight, config: Android.Graphics.Bitmap.Config.Argb8888 ); bitmapFromPlane0.CopyPixelsFromBuffer(planes[0].Buffer); var imagefileInfo = MyAndroidScreenshot.GetScreenshotFileInfo(mImageFileDateTime, mDirName); // 传入目录名称 if (imagefileInfo.Directory.Exists == false) { imagefileInfo.Directory.Create(); } string imageFile = imagefileInfo.FullName; // bitmapFromPlane0 多增加的长度减至 屏幕的 Width bitmapToSave = Android.Graphics.Bitmap.CreateBitmap(bitmapFromPlane0, 0, 0, mWidth, mHeight); using (System.IO.FileStream stream = new System.IO.FileStream(path: imageFile, System.IO.FileMode.CreateNew)) { bitmapToSave.Compress(Android.Graphics.Bitmap.CompressFormat.Png, 60, stream); // 压缩图片 // TODO 控制图片质量 stream.Flush(); } // 发送广播 Android.App.Application.Context.SendBroadcast ( new Android.Content.Intent ( action: Android.Content.Intent.ActionMediaScannerScanFile, uri: Android.Net.Uri.FromFile(new Java.IO.File(imageFile)) ) ); System.Diagnostics.Debug.WriteLine("MyImageReaderListener-OnImageAvailable - 成功保存屏幕截图"); } } } catch (Exception e) { System.Diagnostics.Debug.WriteLine("MyImageReaderListener-OnImageAvailable - 捕获异常"); System.Diagnostics.Debug.WriteLine(e.GetFullInfo()); System.Diagnostics.Debugger.Break(); } finally { if (bitmapFromPlane0 != null) { bitmapFromPlane0.Recycle(); bitmapFromPlane0 = null; } if (image != null) { image.Close(); image = null; } MyAndroidScreenshot.GetInstance().ReleaseAfterScreenCaptureSave(); MyAndroidScreenshot.s_IsRunning.Set(false); } }
private static void _CopyYuv445345To(this ANDROIDIMAGE src, SpanBitmap dst) { // http://werner-dittmann.blogspot.com/2016/03/solving-some-mysteries-about-androids.html if (src == null) { throw new ArgumentNullException(nameof(src)); } if (src.Format != ANDROIDGFX.ImageFormatType.Yuv420888) { throw new ArgumentNullException(nameof(src.Format)); } if (dst.PixelFormat != Pixel.BGR24.Format) { throw new ArgumentNullException(nameof(dst.PixelFormat)); } var planes = src.GetPlanes(); var yPlane = planes[0].Buffer; var uPlane = planes[1].Buffer; var vPlane = planes[2].Buffer; int total = yPlane.Capacity(); int uvCapacity = uPlane.Capacity(); int width = planes[0].RowStride; int yPos = 0; for (int y = 0; y < src.Height; y++) { int uvPos = (y >> 1) * width; var dstRow = dst.UseScanlineBytes(y); for (int x = 0; x < width; x++) { if (uvPos >= uvCapacity - 1) { break; } if (yPos >= total) { break; } int y1 = yPlane.Get(yPos++) & 0xff; /* * The ordering of the u (Cb) and v (Cr) bytes inside the planes is a * bit strange. The _first_ byte of the u-plane and the _second_ byte * of the v-plane build the u/v pair and belong to the first two pixels * (y-bytes), thus usual YUV 420 behavior. What the Android devs did * here (IMHO): just copy the interleaved NV21 U/V data to two planes * but keep the offset of the interleaving. */ int u = (uPlane.Get(uvPos) & 0xff) - 128; int v = (vPlane.Get(uvPos + 1) & 0xff) - 128; if ((x & 1) == 1) { uvPos += 2; } // This is the integer variant to convert YCbCr to RGB, NTSC values. // formulae found at // https://software.intel.com/en-us/android/articles/trusted-tools-in-the-new-android-world-optimization-techniques-from-intel-sse-intrinsics-to // and on StackOverflow etc. int y1192 = 1192 * y1; int r = (y1192 + 1634 * v); int g = (y1192 - 833 * v - 400 * u); int b = (y1192 + 2066 * u); r = (r < 0) ? 0 : ((r > 262143) ? 262143 : r); g = (g < 0) ? 0 : ((g > 262143) ? 262143 : g); b = (b < 0) ? 0 : ((b > 262143) ? 262143 : b); dstRow[x * 3 + 0] = (Byte)(b >> 10); dstRow[x * 3 + 1] = (Byte)(g >> 10); dstRow[x * 3 + 2] = (Byte)(r >> 10); } } }