【问题标题】:iOS Screenshot as System.Drawing.Bitmap (Xamarin) from Background AppiOS 屏幕截图为来自后台应用程序的 System.Drawing.Bitmap (Xamarin)
【发布时间】:2017-02-27 05:42:53
【问题描述】:

对于越狱的 iOS 设备上的私人应用(=不发布在任何应用商店),我需要截取整个屏幕的屏幕截图,以免发送到背景。

已发布类似问题

以下是我的代码的帖子。我正在寻求有关private System.Drawing.Bitmap ShootScreen()实施的帮助

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;

namespace StackOverflowSnippets
{
    public sealed class ScreenshooterThread
    {
        private Thread _t = null;                   // Thread-Object: Execution-Helper
        private Boolean _terminate = false;         // Stop current execution?
        private Int32 _intervalMS = 0;              // Take Screenshots every ? MS
        private Queue<Bitmap> _q;                   // Queue to store the Screenshots

        #region Interface
        /// <summary>
        /// Creates a Screenshooter
        /// </summary>
        /// <param name="intervalMS">Defines every how many MS a screenshot should be taken</param>
        public ScreenshooterThread(Int32 intervalMS = 200)
        {
            _intervalMS = intervalMS;
        }

        /// <summary>
        /// Starts taking Screenshots
        /// </summary>
        public void Run()
        {
            if(this.IsRunning || this.IsTerminating)
            {
                throw new InvalidOperationException("ScreenshooterThread is currently running or terminating");
            }

            lock (this)
            {
                _terminate = false;
                _t = new Thread(this.DoWork);
                _t.Start();
            }
        }

        /// <summary>
        /// Stops taking Screenshots
        /// </summary>
        public void Stop()
        {
            if (!this.IsRunning) return; if (this.IsTerminating) return;

            lock(this)
            {
                _terminate = true;
            }
        }

        /// <summary>
        /// Determines whether the Thread is currently running
        /// </summary>
        public Boolean IsRunning
        {
            get
            {
                if (_t == null) return false;

                return _t.IsAlive;
            }
        }
        /// <summary>
        /// Determines whether Thread-Termination has been invoked
        /// </summary>
        public Boolean IsTerminating
        {
            get
            {
                return _terminate;
            }
        }

        /// <summary>
        /// Get a Screenshot from the Queue. Returns null if none available
        /// </summary>
        public Bitmap Deqeue()
        {
            lock(_q)
            {
                if (_q.Count < 1) return null;
                return _q.Dequeue();
            }
        }

        #endregion

        #region Implementation Details
        /// <summary>
        /// Add a Screenshot to the Queue
        /// </summary>
        private void Enqueue(Bitmap b)
        {
            lock(_q)
            {
                _q.Enqueue(b);
            }
        }

        /// <summary>
        /// Task-Implementation while running
        /// </summary>
        private void DoWork()
        {
            while(!_terminate)
            {
                if (_intervalMS > 0) Thread.Sleep(_intervalMS);

                this.Enqueue(this.ShootScreen());
            }

            this.CleanUp();
        }

        /// <summary>
        /// Takes a Screenshot of the device even if the app is in the Background
        /// </summary>
        private System.Drawing.Bitmap ShootScreen()
        {
            // System.Drawing.Bitmap supported by Xamarin
            // https://developer.xamarin.com/api/type/System.Drawing.Bitmap/

            // Method in ObjC: https://stackoverflow.com/questions/33369014/how-to-take-screenshot-of-entire-screen-on-a-jailbroken-ios-device

            throw new NotImplementedException();
        }
        /// <summary>
        /// Preparing for next launch
        /// </summary>
        private void CleanUp()
        {
            lock(this)
            {
                _terminate = false;
                _t = null;
            }
        }
        #endregion
    }
}

PS:截图需要是System.Drawing.Bitmap,因为之后我需要对其进行Pixelwise操作

编辑 1

经过进一步调查,我在http://sharpmobilecode.com/introduction-to-xamarin-what-it-is-what-it-isnt/ 发现以下段落

例如,假设您现有的 C# 代码使用 System.Drawing.Bitmap。这是您编写的多个通用库 桌面应用参考。一种可能的方法如下所示:

using System.Drawing; 

public Bitmap GetBitmapFromCache(string fileName) 
{ 
   return (Bitmap) Image.FromFile(fileName); 
}    

如果要在 Xamarin.iOS 或 Xamarin.Android 应用程序中编译此方法,则会收到编译错误。嗯?之上 进一步调查,您会看到 System.Drawing.BitmapSystem.Drawing.Image 未定义。什么!?!?这是有效的 C# 句法!经过进一步调查,您只看到几个类 System.Drawing 实际上已定义(RectangleF、PointF 等)。在哪里 到底是位图和图像?嗯,这些是有充分理由的 Mono 框架中没有实现类。这是因为他们 不兼容跨平台。

这到底是什么意思?让我们看一下 System.Drawing MSDN 上的文档。它指出,“System.Drawing 命名空间 提供对 GDI+ 基本图形功能的访问。”。什么是 GDI+? GDI+(图形设备接口)是一个图形库 (Win32),它是 特定于 Windows 操作系统。所以在一个引擎盖下 System.Drawing.Bitmap,是一个 Win32 实现,与 Windows 桌面/服务器操作系统。这意味着 System.Drawing.Bitmap 和 System.Drawing.Image 是平台相关的, 并且仅适用于 Windows 桌面/服务器应用程序。你将无法 在 iOS 应用、Android 应用甚至 Windows Phone 上使用这些类 应用。那么如何在 iOS 或 Android 中使用当前的 C# 代码 应用程序?稍作修改如下:

public byte[] GetBitmapFromCache(string fileName) 
{ 
    return File.ReadAllBytes(fileName); 
} 

iOS 和 Android 没有 GDI+ 位图的概念 (System.Drawing.Bitmap),但是,每个平台都知道如何转换 一个字节数组自己实现的位图。使用 iOS,您可以从字节数组创建 UIImage,而在 Android 您可以从同一个数组创建一个 Android.Graphics.Bitmap。

【问题讨论】:

    标签: c# ios xamarin bitmap


    【解决方案1】:

    http://sharpmobilecode.com/introduction-to-xamarin-what-it-is-what-it-isnt/ 中所述,无法创建System.Drawing.Bitmap,因为System.Drawing 命名空间提供了对Windows 操作系统特有的GDI+ 基础图形功能的访问,因此在iOS 上根本不可用。

    但是,可以将屏幕截图创建为UIImage,如下所示

    1. How to take screenshot of entire screen on a Jailbroken iOS Device? 表明,存在一个私有函数 _UICreateScreenUIImage(void),它返回所需的屏幕截图。为了访问这个函数,必须声明它

      using System.Runtime.InteropServices;
      using ObjCRuntime;
      
      [DLLImport(/*ObjCRuntime.*/Constants.UIKitLibrary)]
      extern static IntPtr _UICreateScreenUIImage();
      
    2. 调用时,返回的IntPtr指向一个原生的UIImage,需要包装成一个托管对象,由Runtime.GetNSObject(IntPtr)完成

      IntPtr ptr = _UICreateScreenUIImage();
      UIImage uiimg = Runtime.GetNSObject(ptr) as UIImage;
      

      生成的uiimg 包含屏幕截图

    所附图片包含一个关于如何创建屏幕截图并将其保存为.jpeg的简约示例

    还有一个应用程序在后台时屏幕截图的示例

    【讨论】:

      猜你喜欢
      • 2012-02-28
      • 2013-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-01
      • 1970-01-01
      • 2013-09-11
      相关资源
      最近更新 更多