本文介绍了iOS萤幕撷取画面为Background App中的System.Drawing.Bitmap(Xamarin)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于越狱的iOS设备上的私有应用(=不会在任何应用商店上发布),我需要截取整个屏幕的屏幕截图,并将其发送到背景.

For a private app (=not to be published on any appstore) on a jailbroken iOS-Device I need to take screenshots of the entire screen from being sent to the background.

类似的问题已发布

  • iOS: Is it possible to take screenshots while running as a background task? which concluded that it would be impossible on non-jailbroken devices due to iOS's security sandbox
  • How to take screenshots of running iPhone from background app? is yet pending, but also seems to target non-jailbroken devices
  • How to take screenshot of entire screen on a Jailbroken iOS Device? (and somewhat similar jailbroken iOS taking screenshot from background app ) seems to be close to what I am looking for, but the code is written in Objective C and makes use of a mysterious private function _UICreateScreenUIImage() of which I don't know in which module it is defined (so I don't know how to declare it as an external function). Also the screenshot is returned as a UIImage (see http://developer.xamarin.com/api/type/MonoTouch.UIKit.UIImage/ ) which I yet don't know how to convert to a System.Drawing.Bitmap (see https://developer.xamarin.com/api/type/System.Drawing.Bitmap/ ).

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

The following is a post of my code. I am looking for help with the implementation of 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操作

PS: The screenshots need to be a System.Drawing.Bitmap because I need to perform Pixelwise operations on it afterwards

编辑1

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

Upon further investigation I found on http://sharpmobilecode.com/introduction-to-xamarin-what-it-is-what-it-isnt/ the following paragraph

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框架中实现.因为他们 跨平台不兼容.

If you were to compile this method in a Xamarin.iOS or Xamarin.Android app,you would get a compile error. Huh? Upon further investigation, you would see that System.Drawing.Bitmap and System.Drawing.Image are not define. What!?!? That’s valid C# syntax! Upon further investigation, you only see a few classes in System.Drawing are actually defined (RectangleF, PointF, etc). Where the heck is Bitmap and Image? Well, there is a good reason these classes are not implemented in the Mono Framework. It’s because they are not cross platform compatible.

那到底是什么意思?让我们看一下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#代码 应用程序?进行如下修改:

What does that mean exactly? Let’s take a look at the System.Drawing documentation on MSDN. It states, "The System.Drawing namespace provides access to GDI+ basic graphics functionality.". What is GDI+? GDI+ (Graphics Device Interface) is a graphics library (Win32) that is specific to the Windows Operating System. So underneath the hood of a System.Drawing.Bitmap, is a Win32 implementation that ties into the Windows Desktop/Server Operating systems. That means System.Drawing.Bitmap and System.Drawing.Image are platform dependent, and only work on Windows Desktop/Server apps. You will not be able to use these classes on iOS app, Android apps, or even Windows Phone apps. So how can you use this current C# code in an iOS or Android app? With a slight modification like this:

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

iOS和Android没有GDI +位图的概念 (System.Drawing.Bitmap),但是,每个平台都知道如何转换 将字节数组转换为自己执行的位图.使用 iOS,您可以根据字节数组创建UIImage,并且在Android中 您可以从同一数组创建一个Android.Graphics.Bitmap.

iOS and Android have no concept of GDI+ bitmap (System.Drawing.Bitmap), however, each platform knows how to convert an array of bytes into their own implementation of a bitmap. Using iOS, you can create a UIImage from an array of bytes, and in Android you can create an Android.Graphics.Bitmap from that same array.

推荐答案

http://sharpmobilecode.com/introduction-to-xamarin-what-it-is-what-it-isnt/不能创建System.Drawing.Bitmap,因为System.Drawing名称空间提供对GDI +基本图形功能的访问,该功能特定于Windows操作系统,因此在iOS上根本不可用.

As stated under http://sharpmobilecode.com/introduction-to-xamarin-what-it-is-what-it-isnt/ it is not possible to create a System.Drawing.Bitmap because the System.Drawing namespace provides access to GDI+ basics graphics functionality which is specific to the Windows OS and therefore simply not available on iOS.

不过,可以按以下方式将屏幕截图创建为UIImage

It is however possible to create a screenshot as an UIImage as follows

  1. 如何是否显示了越狱iOS设备上整个屏幕的屏幕截图?,是否存在一个私有功能_UICreateScreenUIImage(void),该功能可以返回所需的屏幕截图.为了访问此功能,必须对其进行声明

  1. How to take screenshot of entire screen on a Jailbroken iOS Device? showed, that there exists a private function _UICreateScreenUIImage(void) that returns the desired screenshot. In order to access this function, it must be declared

using System.Runtime.InteropServices;
using ObjCRuntime;

[DLLImport(/*ObjCRuntime.*/Constants.UIKitLibrary)]
extern static IntPtr _UICreateScreenUIImage();

  • 调用时,返回的IntPtr指向本机UIImage,需要将其包装到托管对象中,这由Runtime.GetNSObject(IntPtr)

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

    生成的uiimg包含屏幕截图

    所附图片包含有关如何创建屏幕截图并将其另存为.jpeg

    The attached picture contains a minimalistic example on how to create a screenshot and save it as a .jpeg

    以及该应用程序在后台时屏幕截图的示例

    And an example of what a screenshot might look like when the app is in the background

    这篇关于iOS萤幕撷取画面为Background App中的System.Drawing.Bitmap(Xamarin)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

  • 09-12 20:27