AndroidのMediaProjectionを使ってスクリーンショットを撮る ~Delphiでお手軽プログラミング
MediaProjectionのAndroid用ソースコード
Button1を押すと画面のスクリーンショットをImage1に表示します。unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, System.Messaging, FMX.Controls.Presentation, Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.Media, Androidapi.JNIBridge, FMX.Objects, Androidapi.JNI.Hardware; type TOnImageAvailable = procedure (reader: JImageReader) of object; TImageAvailableListener=class(TJavaLocal,JImageReader_OnImageAvailableListener) private FOnImageAvailable: TOnImageAvailable; public procedure OnImageAvailable(reader:JImageReader);cdecl; property OnImgAvailable: TOnImageAvailable read FOnImageAvailable write FOnImageAvailable; end; TForm1 = class(TForm) Button1: TButton; Image1: TImage; procedure Button1Click(Sender: TObject); private { private 宣言 } MPManager: JMediaProjectionManager; FMessageSubscriptionID:integer; FVd:JVirtualDisplay; ImageAvailableListener:TImageAvailableListener; procedure HandleActivityMessage(const Sender: TObject; const M: TMessage); function OnActivityResult(RequestCode, ResultCode: Integer; Itt: JIntent ): Boolean; procedure OnImageAvailable(reader: JImageReader); public { public 宣言 } end; var Form1: TForm1; const REQUEST_CODE_SCREEN_CAPTURE:integer=100;//任意の整数 implementation {$R *.fmx} Uses Androidapi.Jni.JavaTypes, Androidapi.Helpers, Androidapi.JNI.os, Androidapi.JNI.App, FMX.Helpers.Android, FMX.Surfaces, Androidapi.JNI.util ; procedure TForm1.Button1Click(Sender: TObject); var MPObj:JObject; begin FMessageSubscriptionID := TMessageManager.DefaultManager.SubscribeToMessage( TMessageResultNotification, HandleActivityMessage ); MPObj:=TAndroidHelper.Activity.getSystemService( TJContext.JavaClass.MEDIA_PROJECTION_SERVICE ); MPManager:=TJMediaProjectionManager.Wrap( (MPObj as ILocalObject).GetObjectID ); TAndroidHelper.Activity.startActivityForResult( MPManager.createScreenCaptureIntent(), REQUEST_CODE_SCREEN_CAPTURE ); end; procedure TForm1.HandleActivityMessage(const Sender: TObject; const M: TMessage); begin if M is TMessageResultNotification then OnActivityResult( TMessageResultNotification(M).RequestCode, TMessageResultNotification(M).ResultCode, TMessageResultNotification(M).Value ); end; function TForm1.OnActivityResult( RequestCode, ResultCode: Integer; Itt: JIntent ): Boolean; var MProjection: JMediaProjection; ImgReader: JImageReader; handler: JHandler; DisplayMetrics: JDisplayMetrics; Dencity: integer; begin result := false; if RequestCode=REQUEST_CODE_SCREEN_CAPTURE then begin if ResultCode = TJActivity.JavaClass.RESULT_OK then begin MProjection:=MpManager.getMediaProjection(ResultCode,Itt); if MProjection <> nil then begin //RGBA_8888を使用する必要がある ImgReader:=TJImageReader.JavaClass.newInstance( screen.Width, screen.Height, TJPixelFormat.JavaClass.RGBA_8888 ,2); handler:=TJHandler.JavaClass.init(); DisplayMetrics := TAndroidHelper.DisplayMetrics(); TAndroidHelper.Display.getMetrics(DisplayMetrics); Dencity:=DisplayMetrics.densityDpi; FVd:=MProjection.createVirtualDisplay( StringToJString('ScreenCaptureTest'), screen.Width, screen.Height, Dencity, TJDisplayManager.JavaClass.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR or TJDisplayManager.JavaClass.VIRTUAL_DISPLAY_FLAG_PUBLIC, ImgReader.getSurface(), nil, handler ); ImageAvailableListener:=TImageAvailableListener.Create; ImageAvailableListener.OnImgAvailable:=OnImageAvailable; ImgReader.setOnImageAvailableListener( ImageAvailableListener, handler ); end; result := true; end else begin showmessage('キャンセルされた'); end; end; end; procedure TForm1.OnImageAvailable(reader: JImageReader); var Img: JImage; JBuf: JByteBuffer; JBmp: JBitmap; JBmpSfc: TBitmapSurface; JImgPlane:JImage_Plane; PixelStride,RowStride,RowPadding:Integer; begin Img := reader.acquireLatestImage; if Img <> nil then begin JImgPlane:=Img.getPlanes[0]; JBuf:=JImgPlane.getBuffer(); if JBuf <> nil then begin PixelStride:=JImgPlane.getPixelStride; RowStride:=JImgPlane.getRowStride; RowPadding:=RowStride-PixelStride*Screen.Width; JBmp:=TJBitmap.JavaClass.createBitmap( Screen.Width+RowPadding div PixelStride, Screen.Height, TJBitmap_Config.JavaClass.ARGB_8888 ); JBmp.copyPixelsFromBuffer(JBuf); if JBmp <> nil then begin JBmpSfc := TBitmapSurface.Create; JBitmapToSurface(JBmp, JBmpSfc); Image1.Bitmap.Assign(JBmpSfc); JBmpSfc.Free; end; end; Img.close; end; end; { TImageAvailableListener } procedure TImageAvailableListener.OnImageAvailable(reader: JImageReader); begin if Assigned(FonImageAvailable) then begin FOnImageAvailable(reader); end; end; end.