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.