@intuiface/capacitor-plugin-screenshot 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/IntuifaceCapacitorPluginScreenshot.podspec +17 -0
- package/LICENSE +21 -0
- package/README.md +93 -0
- package/android/build.gradle +58 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/intuiface/plugins/screenshot/CapacitorScreenshot.java +11 -0
- package/android/src/main/java/com/intuiface/plugins/screenshot/CapacitorScreenshotPlugin.java +204 -0
- package/android/src/main/java/com/intuiface/plugins/screenshot/ScreenCaptureManager.java +69 -0
- package/android/src/main/java/com/intuiface/plugins/screenshot/ScreenCaptureService.java +83 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/android/src/main/res/values/refs.xml +4 -0
- package/dist/docs.json +90 -0
- package/dist/esm/definitions.d.ts +30 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +8 -0
- package/dist/esm/web.js +61 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +77 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +80 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/CapacitorScreenshot.swift +8 -0
- package/ios/Plugin/CapacitorScreenshotPlugin.h +10 -0
- package/ios/Plugin/CapacitorScreenshotPlugin.m +8 -0
- package/ios/Plugin/CapacitorScreenshotPlugin.swift +49 -0
- package/ios/Plugin/Info.plist +24 -0
- package/package.json +79 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
4
|
+
|
5
|
+
Pod::Spec.new do |s|
|
6
|
+
s.name = 'IntuifaceCapacitorPluginScreenshot'
|
7
|
+
s.version = package['version']
|
8
|
+
s.summary = package['description']
|
9
|
+
s.license = package['license']
|
10
|
+
s.homepage = package['repository']['url']
|
11
|
+
s.author = package['author']
|
12
|
+
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
|
13
|
+
s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
|
14
|
+
s.ios.deployment_target = '13.0'
|
15
|
+
s.dependency 'Capacitor'
|
16
|
+
s.swift_version = '5.1'
|
17
|
+
end
|
package/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 Intuiface
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# capacitor-plugin-screenshot
|
2
|
+
|
3
|
+
Capacitor plugin to take screenshot for iOS and Android devices.
|
4
|
+
|
5
|
+
The main goal of this plugin is to be able to take a screenshot of the application exactly as you see it. Even if there are playing videos, an iframe with some content, a cross-origin CSS...etc.
|
6
|
+
|
7
|
+
This plugin uses the `takeSnapshot` method of the `WKWebView` for iOS : https://developer.apple.com/documentation/webkit/wkwebview/2873260-takesnapshot.
|
8
|
+
|
9
|
+
And for Android, the `MediaProjection` API : https://developer.android.com/reference/android/media/projection/MediaProjection.
|
10
|
+
|
11
|
+
For the web, `MediaDevices` is use to cast the browser tab : https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia.
|
12
|
+
|
13
|
+
## Install
|
14
|
+
|
15
|
+
```bash
|
16
|
+
npm install @intuiface/capacitor-plugin-screenshot
|
17
|
+
npx cap sync
|
18
|
+
```
|
19
|
+
|
20
|
+
## API
|
21
|
+
|
22
|
+
<docgen-index>
|
23
|
+
|
24
|
+
* [`getScreenshot(...)`](#getscreenshot)
|
25
|
+
* [Interfaces](#interfaces)
|
26
|
+
|
27
|
+
</docgen-index>
|
28
|
+
|
29
|
+
<docgen-api>
|
30
|
+
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
|
31
|
+
|
32
|
+
### getScreenshot(...)
|
33
|
+
|
34
|
+
```typescript
|
35
|
+
getScreenshot(options: ScreenshotOptions) => Promise<ScreenshotValue | null>
|
36
|
+
```
|
37
|
+
|
38
|
+
Function to take a screenshot
|
39
|
+
|
40
|
+
| Param | Type | Description |
|
41
|
+
| ------------- | --------------------------------------------------------------- | ------------------------------------------------- |
|
42
|
+
| **`options`** | <code><a href="#screenshotoptions">ScreenshotOptions</a></code> | : options with quality desired for the screenshot |
|
43
|
+
|
44
|
+
**Returns:** <code>Promise<<a href="#screenshotvalue">ScreenshotValue</a> | null></code>
|
45
|
+
|
46
|
+
--------------------
|
47
|
+
|
48
|
+
|
49
|
+
### Interfaces
|
50
|
+
|
51
|
+
|
52
|
+
#### ScreenshotValue
|
53
|
+
|
54
|
+
| Prop | Type | Description |
|
55
|
+
| ------------ | ------------------- | ------------------------------------------------- |
|
56
|
+
| **`base64`** | <code>string</code> | The base64 string of the screenshot. Can be null |
|
57
|
+
| **`URI`** | <code>string</code> | The file uri where the image is saved Can be null |
|
58
|
+
|
59
|
+
|
60
|
+
#### ScreenshotOptions
|
61
|
+
|
62
|
+
| Prop | Type | Description |
|
63
|
+
| ------------- | ------------------- | ------------------------------------------- |
|
64
|
+
| **`quality`** | <code>number</code> | The quality of the screenshot between 0-100 |
|
65
|
+
| **`name`** | <code>string</code> | The name of the file to save |
|
66
|
+
|
67
|
+
</docgen-api>
|
68
|
+
|
69
|
+
---
|
70
|
+
|
71
|
+
## iOS
|
72
|
+
|
73
|
+
iOS version 11+ is supported.
|
74
|
+
|
75
|
+
Nothing more to do, it should work by calling the `getScreenshot` function.
|
76
|
+
|
77
|
+
|
78
|
+
## Android
|
79
|
+
|
80
|
+
Android Version 6+ is supported.
|
81
|
+
|
82
|
+
To be able to take screenshot on Android, you have to declare a foreground service in the `AndroidManifest.xml` in the application tag :
|
83
|
+
|
84
|
+
```xml
|
85
|
+
<service android:enabled="true" android:foregroundServiceType="mediaProjection" android:name="com.intuiface.plugins.screenshot.ScreenCaptureService" />
|
86
|
+
```
|
87
|
+
|
88
|
+
The foreground service will ask you to cast your screen and this is mandatory to take screenshot with the `MediaProjection` API.
|
89
|
+
|
90
|
+
|
91
|
+
## License
|
92
|
+
|
93
|
+
The scripts and documentation in this project are released under the [MIT License](./LICENSE)
|
@@ -0,0 +1,58 @@
|
|
1
|
+
ext {
|
2
|
+
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
3
|
+
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.6.1'
|
4
|
+
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.5'
|
5
|
+
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.5.1'
|
6
|
+
}
|
7
|
+
|
8
|
+
buildscript {
|
9
|
+
repositories {
|
10
|
+
google()
|
11
|
+
mavenCentral()
|
12
|
+
}
|
13
|
+
dependencies {
|
14
|
+
classpath 'com.android.tools.build:gradle:8.0.0'
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
apply plugin: 'com.android.library'
|
19
|
+
|
20
|
+
android {
|
21
|
+
namespace "com.intuiface.plugins.screenshot"
|
22
|
+
compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 33
|
23
|
+
defaultConfig {
|
24
|
+
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
|
25
|
+
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 33
|
26
|
+
versionCode 1
|
27
|
+
versionName "1.0"
|
28
|
+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
29
|
+
}
|
30
|
+
buildTypes {
|
31
|
+
release {
|
32
|
+
minifyEnabled false
|
33
|
+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
34
|
+
}
|
35
|
+
}
|
36
|
+
lintOptions {
|
37
|
+
abortOnError false
|
38
|
+
}
|
39
|
+
compileOptions {
|
40
|
+
sourceCompatibility JavaVersion.VERSION_17
|
41
|
+
targetCompatibility JavaVersion.VERSION_17
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
repositories {
|
46
|
+
google()
|
47
|
+
mavenCentral()
|
48
|
+
}
|
49
|
+
|
50
|
+
|
51
|
+
dependencies {
|
52
|
+
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
53
|
+
implementation project(':capacitor-android')
|
54
|
+
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
55
|
+
testImplementation "junit:junit:$junitVersion"
|
56
|
+
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
57
|
+
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
58
|
+
}
|
@@ -0,0 +1,204 @@
|
|
1
|
+
package com.intuiface.plugins.screenshot;
|
2
|
+
|
3
|
+
import android.annotation.SuppressLint;
|
4
|
+
import android.app.Activity;
|
5
|
+
import android.content.Intent;
|
6
|
+
import android.graphics.Bitmap;
|
7
|
+
import android.graphics.PixelFormat;
|
8
|
+
import android.hardware.display.DisplayManager;
|
9
|
+
import android.hardware.display.VirtualDisplay;
|
10
|
+
import android.media.Image;
|
11
|
+
import android.media.ImageReader;
|
12
|
+
import android.media.projection.MediaProjection;
|
13
|
+
import android.media.projection.MediaProjectionManager;
|
14
|
+
import android.os.Build;
|
15
|
+
import android.os.Handler;
|
16
|
+
import android.os.HandlerThread;
|
17
|
+
import android.util.Base64;
|
18
|
+
import android.util.DisplayMetrics;
|
19
|
+
import androidx.activity.result.ActivityResult;
|
20
|
+
import androidx.activity.result.ActivityResultCallback;
|
21
|
+
import androidx.activity.result.ActivityResultLauncher;
|
22
|
+
import androidx.activity.result.contract.ActivityResultContracts;
|
23
|
+
import com.getcapacitor.JSObject;
|
24
|
+
import com.getcapacitor.Plugin;
|
25
|
+
import com.getcapacitor.PluginCall;
|
26
|
+
import com.getcapacitor.PluginMethod;
|
27
|
+
import com.getcapacitor.annotation.CapacitorPlugin;
|
28
|
+
import java.io.ByteArrayOutputStream;
|
29
|
+
import java.io.File;
|
30
|
+
import java.io.FileNotFoundException;
|
31
|
+
import java.io.FileOutputStream;
|
32
|
+
import java.io.IOException;
|
33
|
+
import java.nio.ByteBuffer;
|
34
|
+
|
35
|
+
@CapacitorPlugin(name = "CapacitorScreenshot", requestCodes = { 1 })
|
36
|
+
public class CapacitorScreenshotPlugin extends Plugin {
|
37
|
+
|
38
|
+
private MediaProjectionManager mediaProjectionManager;
|
39
|
+
private MediaProjection mediaProjection;
|
40
|
+
|
41
|
+
private ActivityResultLauncher<Intent> mediaProjectionActivityLauncher;
|
42
|
+
|
43
|
+
private PluginCall savedCall;
|
44
|
+
|
45
|
+
@Override
|
46
|
+
public void load() {
|
47
|
+
mediaProjectionActivityLauncher =
|
48
|
+
getActivity()
|
49
|
+
.registerForActivityResult(
|
50
|
+
new ActivityResultContracts.StartActivityForResult(),
|
51
|
+
new ActivityResultCallback<ActivityResult>() {
|
52
|
+
@Override
|
53
|
+
public void onActivityResult(ActivityResult result) {
|
54
|
+
if (result.getResultCode() == Activity.RESULT_OK) {
|
55
|
+
assert result.getData() != null;
|
56
|
+
mediaProjection = mediaProjectionManager.getMediaProjection(result.getResultCode(), result.getData());
|
57
|
+
startScreenshotCapture(mediaProjection);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
);
|
62
|
+
}
|
63
|
+
|
64
|
+
@PluginMethod
|
65
|
+
public void getScreenshot(PluginCall call) {
|
66
|
+
if (mediaProjection != null) {
|
67
|
+
savedCall = call;
|
68
|
+
startScreenshotCapture(mediaProjection);
|
69
|
+
} else {
|
70
|
+
ScreenCaptureManager screenCaptureManager = new ScreenCaptureManager(getContext());
|
71
|
+
screenCaptureManager.startForeground();
|
72
|
+
|
73
|
+
getBridge()
|
74
|
+
.getActivity()
|
75
|
+
.runOnUiThread(
|
76
|
+
new Runnable() {
|
77
|
+
@Override
|
78
|
+
public void run() {
|
79
|
+
Activity activity = getBridge().getActivity();
|
80
|
+
if (activity != null) {
|
81
|
+
mediaProjectionManager =
|
82
|
+
(MediaProjectionManager) activity.getSystemService(Activity.MEDIA_PROJECTION_SERVICE);
|
83
|
+
|
84
|
+
savedCall = call;
|
85
|
+
Intent projectionIntent = mediaProjectionManager.createScreenCaptureIntent();
|
86
|
+
mediaProjectionActivityLauncher.launch(projectionIntent);
|
87
|
+
} else {
|
88
|
+
call.reject("Activity is null");
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
92
|
+
);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
private void startScreenshotCapture(MediaProjection mediaProjection) {
|
97
|
+
HandlerThread handlerThread = new HandlerThread("ScreenshotThread");
|
98
|
+
handlerThread.start();
|
99
|
+
|
100
|
+
final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
|
101
|
+
int screenWidth = metrics.widthPixels;
|
102
|
+
int screenHeight = metrics.heightPixels;
|
103
|
+
|
104
|
+
Handler handler = new Handler(handlerThread.getLooper());
|
105
|
+
|
106
|
+
int screenDensity = metrics.densityDpi;
|
107
|
+
|
108
|
+
// Create an ImageReader to capture the screen content
|
109
|
+
@SuppressLint("WrongConstant")
|
110
|
+
ImageReader imageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 1);
|
111
|
+
// Create a VirtualDisplay using the mediaProjection and imageReader
|
112
|
+
final VirtualDisplay virtualDisplay = mediaProjection.createVirtualDisplay(
|
113
|
+
"ScreenCapture",
|
114
|
+
screenWidth,
|
115
|
+
screenHeight,
|
116
|
+
screenDensity,
|
117
|
+
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
118
|
+
imageReader.getSurface(),
|
119
|
+
null,
|
120
|
+
handler
|
121
|
+
);
|
122
|
+
|
123
|
+
// Handle the captured images from the ImageReader
|
124
|
+
imageReader.setOnImageAvailableListener(
|
125
|
+
reader -> {
|
126
|
+
Image image = imageReader.acquireLatestImage();
|
127
|
+
if (image != null) {
|
128
|
+
// Process the captured image
|
129
|
+
processScreenshot(image);
|
130
|
+
// Release the image resources
|
131
|
+
image.close();
|
132
|
+
|
133
|
+
virtualDisplay.release();
|
134
|
+
}
|
135
|
+
},
|
136
|
+
handler
|
137
|
+
);
|
138
|
+
}
|
139
|
+
|
140
|
+
private void processScreenshot(Image image) {
|
141
|
+
if (savedCall != null) {
|
142
|
+
// Convert the Image to a Bitmap
|
143
|
+
Bitmap bitmap = convertImageToBitmap(image);
|
144
|
+
|
145
|
+
// Save or send the bitmap to your server
|
146
|
+
int quality = savedCall.getInt("quality", 100);
|
147
|
+
|
148
|
+
JSObject ret = new JSObject();
|
149
|
+
String base64Image = convertBitmapToBase64(bitmap, quality);
|
150
|
+
|
151
|
+
// save the bitmap as file
|
152
|
+
String filename = savedCall.getString("name", "screenshot");
|
153
|
+
File file = new File(getContext().getFilesDir(), filename + ".png");
|
154
|
+
try (FileOutputStream out = new FileOutputStream(file)) {
|
155
|
+
bitmap.compress(Bitmap.CompressFormat.PNG, quality, out);
|
156
|
+
out.flush();
|
157
|
+
} catch (IOException e) {
|
158
|
+
e.printStackTrace();
|
159
|
+
}
|
160
|
+
|
161
|
+
ret.put("base64", "data:image/png;base64," + base64Image);
|
162
|
+
ret.put("URI", file.toURI());
|
163
|
+
savedCall.resolve(ret);
|
164
|
+
|
165
|
+
// Release any resources
|
166
|
+
bitmap.recycle();
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
private String convertBitmapToBase64(Bitmap bitmap, int quality) {
|
171
|
+
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
172
|
+
bitmap.compress(Bitmap.CompressFormat.PNG, quality, byteArrayOutputStream);
|
173
|
+
byte[] byteArray = byteArrayOutputStream.toByteArray();
|
174
|
+
return Base64.encodeToString(byteArray, Base64.DEFAULT);
|
175
|
+
}
|
176
|
+
|
177
|
+
private Bitmap convertImageToBitmap(Image image) {
|
178
|
+
if (image == null) {
|
179
|
+
return null;
|
180
|
+
}
|
181
|
+
|
182
|
+
Image.Plane[] planes = image.getPlanes();
|
183
|
+
ByteBuffer buffer = planes[0].getBuffer();
|
184
|
+
|
185
|
+
int width = image.getWidth();
|
186
|
+
int height = image.getHeight();
|
187
|
+
int pixelStride = planes[0].getPixelStride();
|
188
|
+
int rowStride = planes[0].getRowStride();
|
189
|
+
int rowPadding = rowStride - pixelStride * width;
|
190
|
+
|
191
|
+
Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
|
192
|
+
bitmap.copyPixelsFromBuffer(buffer);
|
193
|
+
|
194
|
+
// generate the final bitmap at the right size from the bitmap created
|
195
|
+
bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
|
196
|
+
|
197
|
+
// scale but keep ratio
|
198
|
+
int scaledWidth = Math.min(width, 1920);
|
199
|
+
int scaledHeight = height * scaledWidth / width;
|
200
|
+
bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, false);
|
201
|
+
|
202
|
+
return bitmap;
|
203
|
+
}
|
204
|
+
}
|
@@ -0,0 +1,69 @@
|
|
1
|
+
package com.intuiface.plugins.screenshot;
|
2
|
+
|
3
|
+
import android.content.ComponentName;
|
4
|
+
import android.content.Context;
|
5
|
+
import android.content.Intent;
|
6
|
+
import android.content.ServiceConnection;
|
7
|
+
import android.os.IBinder;
|
8
|
+
|
9
|
+
public class ScreenCaptureManager {
|
10
|
+
|
11
|
+
private ScreenCaptureService mService;
|
12
|
+
private Context mContext;
|
13
|
+
private State currentState = State.UNBIND_SERVICE;
|
14
|
+
|
15
|
+
/** Defines callbacks for service binding, passed to bindService() */
|
16
|
+
private final ServiceConnection connection = new ServiceConnection() {
|
17
|
+
@Override
|
18
|
+
public void onServiceConnected(ComponentName className, IBinder service) {
|
19
|
+
// We've bound to ScreenCaptureService, cast the IBinder and get ScreenCaptureService instance
|
20
|
+
ScreenCaptureService.LocalBinder binder = (ScreenCaptureService.LocalBinder) service;
|
21
|
+
mService = binder.getService();
|
22
|
+
if (currentState == State.START_FOREGROUND) {
|
23
|
+
mService.startForeground();
|
24
|
+
} else {
|
25
|
+
currentState = State.BIND_SERVICE;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
@Override
|
30
|
+
public void onServiceDisconnected(ComponentName arg0) {}
|
31
|
+
};
|
32
|
+
|
33
|
+
/**
|
34
|
+
* An enum describing the possible states of a ScreenCaptureManager.
|
35
|
+
*/
|
36
|
+
public enum State {
|
37
|
+
BIND_SERVICE,
|
38
|
+
START_FOREGROUND,
|
39
|
+
END_FOREGROUND,
|
40
|
+
UNBIND_SERVICE
|
41
|
+
}
|
42
|
+
|
43
|
+
public ScreenCaptureManager(Context context) {
|
44
|
+
mContext = context;
|
45
|
+
bindService();
|
46
|
+
}
|
47
|
+
|
48
|
+
private void bindService() {
|
49
|
+
Intent intent = new Intent(mContext, ScreenCaptureService.class);
|
50
|
+
mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
|
51
|
+
}
|
52
|
+
|
53
|
+
public void startForeground() {
|
54
|
+
if (mService != null) {
|
55
|
+
mService.startForeground();
|
56
|
+
}
|
57
|
+
currentState = State.START_FOREGROUND;
|
58
|
+
}
|
59
|
+
|
60
|
+
public void endForeground() {
|
61
|
+
mService.endForeground();
|
62
|
+
currentState = State.END_FOREGROUND;
|
63
|
+
}
|
64
|
+
|
65
|
+
public void unbindService() {
|
66
|
+
mContext.unbindService(connection);
|
67
|
+
currentState = State.UNBIND_SERVICE;
|
68
|
+
}
|
69
|
+
}
|
@@ -0,0 +1,83 @@
|
|
1
|
+
package com.intuiface.plugins.screenshot;
|
2
|
+
|
3
|
+
import android.app.Notification;
|
4
|
+
import android.app.NotificationChannel;
|
5
|
+
import android.app.NotificationManager;
|
6
|
+
import android.app.Service;
|
7
|
+
import android.content.Context;
|
8
|
+
import android.content.Intent;
|
9
|
+
import android.os.Binder;
|
10
|
+
import android.os.Build;
|
11
|
+
import android.os.IBinder;
|
12
|
+
|
13
|
+
/**
|
14
|
+
* Foreground service to ask screen capture permission.
|
15
|
+
*/
|
16
|
+
public class ScreenCaptureService extends Service {
|
17
|
+
|
18
|
+
private static final String CHANNEL_ID = "default";
|
19
|
+
private static final String CHANNEL_NAME = "ScreenCapture";
|
20
|
+
|
21
|
+
// Binder given to clients
|
22
|
+
private final IBinder binder = new LocalBinder();
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Class used for the client Binder. We know this service always
|
26
|
+
* runs in the same process as its clients, we don't need to deal with IPC.
|
27
|
+
*/
|
28
|
+
public class LocalBinder extends Binder {
|
29
|
+
|
30
|
+
public ScreenCaptureService getService() {
|
31
|
+
// Return this instance of ScreenCaptureService so clients can call public methods
|
32
|
+
return ScreenCaptureService.this;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
@Override
|
37
|
+
public void onCreate() {
|
38
|
+
super.onCreate();
|
39
|
+
}
|
40
|
+
|
41
|
+
@Override
|
42
|
+
public int onStartCommand(Intent intent, int flags, int startId) {
|
43
|
+
return START_NOT_STICKY;
|
44
|
+
}
|
45
|
+
|
46
|
+
public void startForeground() {
|
47
|
+
NotificationChannel chan = null;
|
48
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
49
|
+
chan = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_NONE);
|
50
|
+
}
|
51
|
+
NotificationManager manager = null;
|
52
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
53
|
+
manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
54
|
+
}
|
55
|
+
assert manager != null;
|
56
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
57
|
+
manager.createNotificationChannel(chan);
|
58
|
+
}
|
59
|
+
|
60
|
+
final int notificationId = (int) System.currentTimeMillis();
|
61
|
+
Notification.Builder notificationBuilder = null;
|
62
|
+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
63
|
+
notificationBuilder = new Notification.Builder(this, CHANNEL_ID);
|
64
|
+
} else {
|
65
|
+
notificationBuilder = new Notification.Builder(this);
|
66
|
+
}
|
67
|
+
Notification notification = notificationBuilder
|
68
|
+
.setOngoing(true)
|
69
|
+
.setContentTitle("ScreenCaptureService is running in the foreground")
|
70
|
+
.setCategory(Notification.CATEGORY_SERVICE)
|
71
|
+
.build();
|
72
|
+
startForeground(notificationId, notification);
|
73
|
+
}
|
74
|
+
|
75
|
+
public void endForeground() {
|
76
|
+
stopForeground(true);
|
77
|
+
}
|
78
|
+
|
79
|
+
@Override
|
80
|
+
public IBinder onBind(Intent intent) {
|
81
|
+
return binder;
|
82
|
+
}
|
83
|
+
}
|
File without changes
|
package/dist/docs.json
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
{
|
2
|
+
"api": {
|
3
|
+
"name": "CapacitorScreenshotPlugin",
|
4
|
+
"slug": "capacitorscreenshotplugin",
|
5
|
+
"docs": "",
|
6
|
+
"tags": [],
|
7
|
+
"methods": [
|
8
|
+
{
|
9
|
+
"name": "getScreenshot",
|
10
|
+
"signature": "(options: ScreenshotOptions) => Promise<ScreenshotValue | null>",
|
11
|
+
"parameters": [
|
12
|
+
{
|
13
|
+
"name": "options",
|
14
|
+
"docs": ": options with quality desired for the screenshot",
|
15
|
+
"type": "ScreenshotOptions"
|
16
|
+
}
|
17
|
+
],
|
18
|
+
"returns": "Promise<ScreenshotValue | null>",
|
19
|
+
"tags": [
|
20
|
+
{
|
21
|
+
"name": "param",
|
22
|
+
"text": "options : options with quality desired for the screenshot"
|
23
|
+
},
|
24
|
+
{
|
25
|
+
"name": "returns",
|
26
|
+
"text": "Promise with the base64 string of the image if available, null instead"
|
27
|
+
}
|
28
|
+
],
|
29
|
+
"docs": "Function to take a screenshot",
|
30
|
+
"complexTypes": [
|
31
|
+
"ScreenshotValue",
|
32
|
+
"ScreenshotOptions"
|
33
|
+
],
|
34
|
+
"slug": "getscreenshot"
|
35
|
+
}
|
36
|
+
],
|
37
|
+
"properties": []
|
38
|
+
},
|
39
|
+
"interfaces": [
|
40
|
+
{
|
41
|
+
"name": "ScreenshotValue",
|
42
|
+
"slug": "screenshotvalue",
|
43
|
+
"docs": "",
|
44
|
+
"tags": [],
|
45
|
+
"methods": [],
|
46
|
+
"properties": [
|
47
|
+
{
|
48
|
+
"name": "base64",
|
49
|
+
"tags": [],
|
50
|
+
"docs": "The base64 string of the screenshot.\nCan be null",
|
51
|
+
"complexTypes": [],
|
52
|
+
"type": "string | undefined"
|
53
|
+
},
|
54
|
+
{
|
55
|
+
"name": "URI",
|
56
|
+
"tags": [],
|
57
|
+
"docs": "The file uri where the image is saved\nCan be null",
|
58
|
+
"complexTypes": [],
|
59
|
+
"type": "string | undefined"
|
60
|
+
}
|
61
|
+
]
|
62
|
+
},
|
63
|
+
{
|
64
|
+
"name": "ScreenshotOptions",
|
65
|
+
"slug": "screenshotoptions",
|
66
|
+
"docs": "",
|
67
|
+
"tags": [],
|
68
|
+
"methods": [],
|
69
|
+
"properties": [
|
70
|
+
{
|
71
|
+
"name": "quality",
|
72
|
+
"tags": [],
|
73
|
+
"docs": "The quality of the screenshot between 0-100",
|
74
|
+
"complexTypes": [],
|
75
|
+
"type": "number"
|
76
|
+
},
|
77
|
+
{
|
78
|
+
"name": "name",
|
79
|
+
"tags": [],
|
80
|
+
"docs": "The name of the file to save",
|
81
|
+
"complexTypes": [],
|
82
|
+
"type": "string | undefined"
|
83
|
+
}
|
84
|
+
]
|
85
|
+
}
|
86
|
+
],
|
87
|
+
"enums": [],
|
88
|
+
"typeAliases": [],
|
89
|
+
"pluginConfigs": []
|
90
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
export interface CapacitorScreenshotPlugin {
|
2
|
+
/**
|
3
|
+
* Function to take a screenshot
|
4
|
+
* @param {ScreenshotOptions} options : options with quality desired for the screenshot
|
5
|
+
* @returns {Promise<ScreenshotValue | null>} Promise with the base64 string of the image if available, null instead
|
6
|
+
*/
|
7
|
+
getScreenshot(options: ScreenshotOptions): Promise<ScreenshotValue | null>;
|
8
|
+
}
|
9
|
+
export interface ScreenshotOptions {
|
10
|
+
/**
|
11
|
+
* The quality of the screenshot between 0-100
|
12
|
+
*/
|
13
|
+
quality: number;
|
14
|
+
/**
|
15
|
+
* The name of the file to save
|
16
|
+
*/
|
17
|
+
name?: string;
|
18
|
+
}
|
19
|
+
export interface ScreenshotValue {
|
20
|
+
/**
|
21
|
+
* The base64 string of the screenshot.
|
22
|
+
* Can be null
|
23
|
+
*/
|
24
|
+
base64?: string;
|
25
|
+
/**
|
26
|
+
* The file uri where the image is saved
|
27
|
+
* Can be null
|
28
|
+
*/
|
29
|
+
URI?: string;
|
30
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface CapacitorScreenshotPlugin {\n /**\n * Function to take a screenshot\n * @param {ScreenshotOptions} options : options with quality desired for the screenshot\n * @returns {Promise<ScreenshotValue | null>} Promise with the base64 string of the image if available, null instead\n */\n getScreenshot(options: ScreenshotOptions): Promise<ScreenshotValue | null>;\n}\n\nexport interface ScreenshotOptions {\n /**\n * The quality of the screenshot between 0-100\n */\n quality: number;\n /**\n * The name of the file to save\n */\n name?: string;\n}\n\nexport interface ScreenshotValue {\n /**\n * The base64 string of the screenshot.\n * Can be null\n */\n base64?: string;\n /**\n * The file uri where the image is saved\n * Can be null\n */\n URI?: string;\n}\n"]}
|
@@ -0,0 +1,7 @@
|
|
1
|
+
import { registerPlugin } from '@capacitor/core';
|
2
|
+
const CapacitorScreenshot = registerPlugin('CapacitorScreenshot', {
|
3
|
+
web: () => import('./web').then(m => new m.CapacitorScreenshotWeb()),
|
4
|
+
});
|
5
|
+
export * from './definitions';
|
6
|
+
export { CapacitorScreenshot };
|
7
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,mBAAmB,GAAG,cAAc,CACxC,qBAAqB,EACrB;IACE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,sBAAsB,EAAE,CAAC;CACrE,CACF,CAAC;AAEF,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,mBAAmB,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { CapacitorScreenshotPlugin } from './definitions';\n\nconst CapacitorScreenshot = registerPlugin<CapacitorScreenshotPlugin>(\n 'CapacitorScreenshot',\n {\n web: () => import('./web').then(m => new m.CapacitorScreenshotWeb()),\n },\n);\n\nexport * from './definitions';\nexport { CapacitorScreenshot };\n"]}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
2
|
+
import type { CapacitorScreenshotPlugin, ScreenshotOptions, ScreenshotValue } from './definitions';
|
3
|
+
export declare class CapacitorScreenshotWeb extends WebPlugin implements CapacitorScreenshotPlugin {
|
4
|
+
private captureStream;
|
5
|
+
private videoCapture;
|
6
|
+
private captureCanvas;
|
7
|
+
getScreenshot(options: ScreenshotOptions): Promise<ScreenshotValue | null>;
|
8
|
+
}
|
package/dist/esm/web.js
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
2
|
+
export class CapacitorScreenshotWeb extends WebPlugin {
|
3
|
+
async getScreenshot(options) {
|
4
|
+
try {
|
5
|
+
if (!this.captureStream) {
|
6
|
+
// display a message ?
|
7
|
+
// get the media device
|
8
|
+
const mediaDevices = navigator.mediaDevices;
|
9
|
+
const width = screen.width * (window.devicePixelRatio || 1);
|
10
|
+
const height = screen.height * (window.devicePixelRatio || 1);
|
11
|
+
// start sharing screen (ask for it)
|
12
|
+
this.captureStream = await mediaDevices.getDisplayMedia({
|
13
|
+
preferCurrentTab: true,
|
14
|
+
audio: false,
|
15
|
+
video: {
|
16
|
+
width,
|
17
|
+
height,
|
18
|
+
},
|
19
|
+
});
|
20
|
+
// create a video tag
|
21
|
+
this.videoCapture = document.createElement('video');
|
22
|
+
// create a canvas
|
23
|
+
this.captureCanvas = document.createElement('canvas');
|
24
|
+
}
|
25
|
+
return new Promise(resolve => {
|
26
|
+
const callbackLoadedMetadata = () => {
|
27
|
+
// unbind from loaded metadata
|
28
|
+
this.videoCapture.removeEventListener('loadedmetadata', callbackLoadedMetadata);
|
29
|
+
// set the canvas size with the video size
|
30
|
+
this.captureCanvas.width = this.videoCapture.videoWidth;
|
31
|
+
this.captureCanvas.height = this.videoCapture.videoHeight;
|
32
|
+
// draw the video into canvas
|
33
|
+
this.captureCanvas
|
34
|
+
.getContext('2d')
|
35
|
+
.drawImage(this.videoCapture, 0, 0);
|
36
|
+
let quality = 1.0;
|
37
|
+
if (options.quality) {
|
38
|
+
quality = options.quality / 100;
|
39
|
+
}
|
40
|
+
// get the image of the canvas
|
41
|
+
const frame = this.captureCanvas.toDataURL('image/jpeg', quality);
|
42
|
+
// pause the video
|
43
|
+
this.videoCapture.pause();
|
44
|
+
// return the image
|
45
|
+
resolve({ base64: frame });
|
46
|
+
};
|
47
|
+
// bind on loaded metadata to draw the video when the video is ready
|
48
|
+
this.videoCapture.onloadedmetadata = callbackLoadedMetadata;
|
49
|
+
// set the src of the video
|
50
|
+
this.videoCapture.srcObject = this.captureStream;
|
51
|
+
// play the video
|
52
|
+
this.videoCapture.play();
|
53
|
+
});
|
54
|
+
}
|
55
|
+
catch (err) {
|
56
|
+
console.error(`Error: ${err}`);
|
57
|
+
return null;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
//# sourceMappingURL=web.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAQ5C,MAAM,OAAO,sBACX,SAAQ,SAAS;IAOjB,KAAK,CAAC,aAAa,CACjB,OAA0B;QAE1B,IAAI;YACF,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;gBACvB,sBAAsB;gBAEtB,uBAAuB;gBACvB,MAAM,YAAY,GAAG,SAAS,CAAC,YAAmB,CAAC;gBACnD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC;gBAC5D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC;gBAE9D,oCAAoC;gBACpC,IAAI,CAAC,aAAa,GAAG,MAAM,YAAY,CAAC,eAAe,CAAC;oBACtD,gBAAgB,EAAE,IAAI;oBACtB,KAAK,EAAE,KAAK;oBACZ,KAAK,EAAE;wBACL,KAAK;wBACL,MAAM;qBACP;iBACF,CAAC,CAAC;gBACH,qBAAqB;gBACrB,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;gBACpD,kBAAkB;gBAClB,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;aACvD;YAED,OAAO,IAAI,OAAO,CAAM,OAAO,CAAC,EAAE;gBAChC,MAAM,sBAAsB,GAAG,GAAG,EAAE;oBAClC,8BAA8B;oBAC9B,IAAI,CAAC,YAAY,CAAC,mBAAmB,CACnC,gBAAgB,EAChB,sBAAsB,CACvB,CAAC;oBACF,0CAA0C;oBAC1C,IAAI,CAAC,aAAa,CAAC,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC;oBACxD,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC;oBAC1D,6BAA6B;oBAC7B,IAAI,CAAC,aAAa;yBACf,UAAU,CAAC,IAAI,CAAC;yBAChB,SAAS,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;oBACtC,IAAI,OAAO,GAAG,GAAG,CAAC;oBAClB,IAAI,OAAO,CAAC,OAAO,EAAE;wBACnB,OAAO,GAAG,OAAO,CAAC,OAAO,GAAG,GAAG,CAAC;qBACjC;oBACD,8BAA8B;oBAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;oBAClE,kBAAkB;oBAClB,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;oBAE1B,mBAAmB;oBACnB,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC7B,CAAC,CAAC;gBAEF,oEAAoE;gBACpE,IAAI,CAAC,YAAY,CAAC,gBAAgB,GAAG,sBAAsB,CAAC;gBAC5D,2BAA2B;gBAC3B,IAAI,CAAC,YAAY,CAAC,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC;gBACjD,iBAAiB;gBACjB,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;YAC3B,CAAC,CAAC,CAAC;SACJ;QAAC,OAAO,GAAG,EAAE;YACZ,OAAO,CAAC,KAAK,CAAC,UAAU,GAAa,EAAE,CAAC,CAAC;YACzC,OAAO,IAAI,CAAC;SACb;IACH,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type {\n CapacitorScreenshotPlugin,\n ScreenshotOptions,\n ScreenshotValue,\n} from './definitions';\n\nexport class CapacitorScreenshotWeb\n extends WebPlugin\n implements CapacitorScreenshotPlugin\n{\n private captureStream: any;\n private videoCapture: any;\n private captureCanvas: any;\n\n async getScreenshot(\n options: ScreenshotOptions,\n ): Promise<ScreenshotValue | null> {\n try {\n if (!this.captureStream) {\n // display a message ?\n\n // get the media device\n const mediaDevices = navigator.mediaDevices as any;\n const width = screen.width * (window.devicePixelRatio || 1);\n const height = screen.height * (window.devicePixelRatio || 1);\n\n // start sharing screen (ask for it)\n this.captureStream = await mediaDevices.getDisplayMedia({\n preferCurrentTab: true,\n audio: false,\n video: {\n width,\n height,\n },\n });\n // create a video tag\n this.videoCapture = document.createElement('video');\n // create a canvas\n this.captureCanvas = document.createElement('canvas');\n }\n\n return new Promise<any>(resolve => {\n const callbackLoadedMetadata = () => {\n // unbind from loaded metadata\n this.videoCapture.removeEventListener(\n 'loadedmetadata',\n callbackLoadedMetadata,\n );\n // set the canvas size with the video size\n this.captureCanvas.width = this.videoCapture.videoWidth;\n this.captureCanvas.height = this.videoCapture.videoHeight;\n // draw the video into canvas\n this.captureCanvas\n .getContext('2d')\n .drawImage(this.videoCapture, 0, 0);\n let quality = 1.0;\n if (options.quality) {\n quality = options.quality / 100;\n }\n // get the image of the canvas\n const frame = this.captureCanvas.toDataURL('image/jpeg', quality);\n // pause the video\n this.videoCapture.pause();\n\n // return the image\n resolve({ base64: frame });\n };\n\n // bind on loaded metadata to draw the video when the video is ready\n this.videoCapture.onloadedmetadata = callbackLoadedMetadata;\n // set the src of the video\n this.videoCapture.srcObject = this.captureStream;\n // play the video\n this.videoCapture.play();\n });\n } catch (err) {\n console.error(`Error: ${err as string}`);\n return null;\n }\n }\n}\n"]}
|
@@ -0,0 +1,77 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
4
|
+
|
5
|
+
var core = require('@capacitor/core');
|
6
|
+
|
7
|
+
const CapacitorScreenshot = core.registerPlugin('CapacitorScreenshot', {
|
8
|
+
web: () => Promise.resolve().then(function () { return web; }).then(m => new m.CapacitorScreenshotWeb()),
|
9
|
+
});
|
10
|
+
|
11
|
+
class CapacitorScreenshotWeb extends core.WebPlugin {
|
12
|
+
async getScreenshot(options) {
|
13
|
+
try {
|
14
|
+
if (!this.captureStream) {
|
15
|
+
// display a message ?
|
16
|
+
// get the media device
|
17
|
+
const mediaDevices = navigator.mediaDevices;
|
18
|
+
const width = screen.width * (window.devicePixelRatio || 1);
|
19
|
+
const height = screen.height * (window.devicePixelRatio || 1);
|
20
|
+
// start sharing screen (ask for it)
|
21
|
+
this.captureStream = await mediaDevices.getDisplayMedia({
|
22
|
+
preferCurrentTab: true,
|
23
|
+
audio: false,
|
24
|
+
video: {
|
25
|
+
width,
|
26
|
+
height,
|
27
|
+
},
|
28
|
+
});
|
29
|
+
// create a video tag
|
30
|
+
this.videoCapture = document.createElement('video');
|
31
|
+
// create a canvas
|
32
|
+
this.captureCanvas = document.createElement('canvas');
|
33
|
+
}
|
34
|
+
return new Promise(resolve => {
|
35
|
+
const callbackLoadedMetadata = () => {
|
36
|
+
// unbind from loaded metadata
|
37
|
+
this.videoCapture.removeEventListener('loadedmetadata', callbackLoadedMetadata);
|
38
|
+
// set the canvas size with the video size
|
39
|
+
this.captureCanvas.width = this.videoCapture.videoWidth;
|
40
|
+
this.captureCanvas.height = this.videoCapture.videoHeight;
|
41
|
+
// draw the video into canvas
|
42
|
+
this.captureCanvas
|
43
|
+
.getContext('2d')
|
44
|
+
.drawImage(this.videoCapture, 0, 0);
|
45
|
+
let quality = 1.0;
|
46
|
+
if (options.quality) {
|
47
|
+
quality = options.quality / 100;
|
48
|
+
}
|
49
|
+
// get the image of the canvas
|
50
|
+
const frame = this.captureCanvas.toDataURL('image/jpeg', quality);
|
51
|
+
// pause the video
|
52
|
+
this.videoCapture.pause();
|
53
|
+
// return the image
|
54
|
+
resolve({ base64: frame });
|
55
|
+
};
|
56
|
+
// bind on loaded metadata to draw the video when the video is ready
|
57
|
+
this.videoCapture.onloadedmetadata = callbackLoadedMetadata;
|
58
|
+
// set the src of the video
|
59
|
+
this.videoCapture.srcObject = this.captureStream;
|
60
|
+
// play the video
|
61
|
+
this.videoCapture.play();
|
62
|
+
});
|
63
|
+
}
|
64
|
+
catch (err) {
|
65
|
+
console.error(`Error: ${err}`);
|
66
|
+
return null;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
var web = /*#__PURE__*/Object.freeze({
|
72
|
+
__proto__: null,
|
73
|
+
CapacitorScreenshotWeb: CapacitorScreenshotWeb
|
74
|
+
});
|
75
|
+
|
76
|
+
exports.CapacitorScreenshot = CapacitorScreenshot;
|
77
|
+
//# sourceMappingURL=plugin.cjs.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst CapacitorScreenshot = registerPlugin('CapacitorScreenshot', {\n web: () => import('./web').then(m => new m.CapacitorScreenshotWeb()),\n});\nexport * from './definitions';\nexport { CapacitorScreenshot };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class CapacitorScreenshotWeb extends WebPlugin {\n async getScreenshot(options) {\n try {\n if (!this.captureStream) {\n // display a message ?\n // get the media device\n const mediaDevices = navigator.mediaDevices;\n const width = screen.width * (window.devicePixelRatio || 1);\n const height = screen.height * (window.devicePixelRatio || 1);\n // start sharing screen (ask for it)\n this.captureStream = await mediaDevices.getDisplayMedia({\n preferCurrentTab: true,\n audio: false,\n video: {\n width,\n height,\n },\n });\n // create a video tag\n this.videoCapture = document.createElement('video');\n // create a canvas\n this.captureCanvas = document.createElement('canvas');\n }\n return new Promise(resolve => {\n const callbackLoadedMetadata = () => {\n // unbind from loaded metadata\n this.videoCapture.removeEventListener('loadedmetadata', callbackLoadedMetadata);\n // set the canvas size with the video size\n this.captureCanvas.width = this.videoCapture.videoWidth;\n this.captureCanvas.height = this.videoCapture.videoHeight;\n // draw the video into canvas\n this.captureCanvas\n .getContext('2d')\n .drawImage(this.videoCapture, 0, 0);\n let quality = 1.0;\n if (options.quality) {\n quality = options.quality / 100;\n }\n // get the image of the canvas\n const frame = this.captureCanvas.toDataURL('image/jpeg', quality);\n // pause the video\n this.videoCapture.pause();\n // return the image\n resolve({ base64: frame });\n };\n // bind on loaded metadata to draw the video when the video is ready\n this.videoCapture.onloadedmetadata = callbackLoadedMetadata;\n // set the src of the video\n this.videoCapture.srcObject = this.captureStream;\n // play the video\n this.videoCapture.play();\n });\n }\n catch (err) {\n console.error(`Error: ${err}`);\n return null;\n }\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
|
package/dist/plugin.js
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
var capacitorCapacitorScreenshot = (function (exports, core) {
|
2
|
+
'use strict';
|
3
|
+
|
4
|
+
const CapacitorScreenshot = core.registerPlugin('CapacitorScreenshot', {
|
5
|
+
web: () => Promise.resolve().then(function () { return web; }).then(m => new m.CapacitorScreenshotWeb()),
|
6
|
+
});
|
7
|
+
|
8
|
+
class CapacitorScreenshotWeb extends core.WebPlugin {
|
9
|
+
async getScreenshot(options) {
|
10
|
+
try {
|
11
|
+
if (!this.captureStream) {
|
12
|
+
// display a message ?
|
13
|
+
// get the media device
|
14
|
+
const mediaDevices = navigator.mediaDevices;
|
15
|
+
const width = screen.width * (window.devicePixelRatio || 1);
|
16
|
+
const height = screen.height * (window.devicePixelRatio || 1);
|
17
|
+
// start sharing screen (ask for it)
|
18
|
+
this.captureStream = await mediaDevices.getDisplayMedia({
|
19
|
+
preferCurrentTab: true,
|
20
|
+
audio: false,
|
21
|
+
video: {
|
22
|
+
width,
|
23
|
+
height,
|
24
|
+
},
|
25
|
+
});
|
26
|
+
// create a video tag
|
27
|
+
this.videoCapture = document.createElement('video');
|
28
|
+
// create a canvas
|
29
|
+
this.captureCanvas = document.createElement('canvas');
|
30
|
+
}
|
31
|
+
return new Promise(resolve => {
|
32
|
+
const callbackLoadedMetadata = () => {
|
33
|
+
// unbind from loaded metadata
|
34
|
+
this.videoCapture.removeEventListener('loadedmetadata', callbackLoadedMetadata);
|
35
|
+
// set the canvas size with the video size
|
36
|
+
this.captureCanvas.width = this.videoCapture.videoWidth;
|
37
|
+
this.captureCanvas.height = this.videoCapture.videoHeight;
|
38
|
+
// draw the video into canvas
|
39
|
+
this.captureCanvas
|
40
|
+
.getContext('2d')
|
41
|
+
.drawImage(this.videoCapture, 0, 0);
|
42
|
+
let quality = 1.0;
|
43
|
+
if (options.quality) {
|
44
|
+
quality = options.quality / 100;
|
45
|
+
}
|
46
|
+
// get the image of the canvas
|
47
|
+
const frame = this.captureCanvas.toDataURL('image/jpeg', quality);
|
48
|
+
// pause the video
|
49
|
+
this.videoCapture.pause();
|
50
|
+
// return the image
|
51
|
+
resolve({ base64: frame });
|
52
|
+
};
|
53
|
+
// bind on loaded metadata to draw the video when the video is ready
|
54
|
+
this.videoCapture.onloadedmetadata = callbackLoadedMetadata;
|
55
|
+
// set the src of the video
|
56
|
+
this.videoCapture.srcObject = this.captureStream;
|
57
|
+
// play the video
|
58
|
+
this.videoCapture.play();
|
59
|
+
});
|
60
|
+
}
|
61
|
+
catch (err) {
|
62
|
+
console.error(`Error: ${err}`);
|
63
|
+
return null;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
var web = /*#__PURE__*/Object.freeze({
|
69
|
+
__proto__: null,
|
70
|
+
CapacitorScreenshotWeb: CapacitorScreenshotWeb
|
71
|
+
});
|
72
|
+
|
73
|
+
exports.CapacitorScreenshot = CapacitorScreenshot;
|
74
|
+
|
75
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
76
|
+
|
77
|
+
return exports;
|
78
|
+
|
79
|
+
})({}, capacitorExports);
|
80
|
+
//# sourceMappingURL=plugin.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst CapacitorScreenshot = registerPlugin('CapacitorScreenshot', {\n web: () => import('./web').then(m => new m.CapacitorScreenshotWeb()),\n});\nexport * from './definitions';\nexport { CapacitorScreenshot };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class CapacitorScreenshotWeb extends WebPlugin {\n async getScreenshot(options) {\n try {\n if (!this.captureStream) {\n // display a message ?\n // get the media device\n const mediaDevices = navigator.mediaDevices;\n const width = screen.width * (window.devicePixelRatio || 1);\n const height = screen.height * (window.devicePixelRatio || 1);\n // start sharing screen (ask for it)\n this.captureStream = await mediaDevices.getDisplayMedia({\n preferCurrentTab: true,\n audio: false,\n video: {\n width,\n height,\n },\n });\n // create a video tag\n this.videoCapture = document.createElement('video');\n // create a canvas\n this.captureCanvas = document.createElement('canvas');\n }\n return new Promise(resolve => {\n const callbackLoadedMetadata = () => {\n // unbind from loaded metadata\n this.videoCapture.removeEventListener('loadedmetadata', callbackLoadedMetadata);\n // set the canvas size with the video size\n this.captureCanvas.width = this.videoCapture.videoWidth;\n this.captureCanvas.height = this.videoCapture.videoHeight;\n // draw the video into canvas\n this.captureCanvas\n .getContext('2d')\n .drawImage(this.videoCapture, 0, 0);\n let quality = 1.0;\n if (options.quality) {\n quality = options.quality / 100;\n }\n // get the image of the canvas\n const frame = this.captureCanvas.toDataURL('image/jpeg', quality);\n // pause the video\n this.videoCapture.pause();\n // return the image\n resolve({ base64: frame });\n };\n // bind on loaded metadata to draw the video when the video is ready\n this.videoCapture.onloadedmetadata = callbackLoadedMetadata;\n // set the src of the video\n this.videoCapture.srcObject = this.captureStream;\n // play the video\n this.videoCapture.play();\n });\n }\n catch (err) {\n console.error(`Error: ${err}`);\n return null;\n }\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#import <UIKit/UIKit.h>
|
2
|
+
|
3
|
+
//! Project version number for Plugin.
|
4
|
+
FOUNDATION_EXPORT double PluginVersionNumber;
|
5
|
+
|
6
|
+
//! Project version string for Plugin.
|
7
|
+
FOUNDATION_EXPORT const unsigned char PluginVersionString[];
|
8
|
+
|
9
|
+
// In this header, you should import all the public headers of your framework using statements like #import <Plugin/PublicHeader.h>
|
10
|
+
|
@@ -0,0 +1,8 @@
|
|
1
|
+
#import <Foundation/Foundation.h>
|
2
|
+
#import <Capacitor/Capacitor.h>
|
3
|
+
|
4
|
+
// Define the plugin using the CAP_PLUGIN Macro, and
|
5
|
+
// each method the plugin supports using the CAP_PLUGIN_METHOD macro.
|
6
|
+
CAP_PLUGIN(CapacitorScreenshotPlugin, "CapacitorScreenshot",
|
7
|
+
CAP_PLUGIN_METHOD(getScreenshot, CAPPluginReturnPromise);
|
8
|
+
)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import Foundation
|
2
|
+
import Capacitor
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Please read the Capacitor iOS Plugin Development Guide
|
6
|
+
* here: https://capacitorjs.com/docs/plugins/ios
|
7
|
+
*/
|
8
|
+
@objc(CapacitorScreenshotPlugin)
|
9
|
+
public class CapacitorScreenshotPlugin: CAPPlugin {
|
10
|
+
private let implementation = CapacitorScreenshot()
|
11
|
+
|
12
|
+
@objc func getScreenshot(_ call: CAPPluginCall) {
|
13
|
+
|
14
|
+
let quality = ((call.getDouble("quality") ?? 100) / 100)
|
15
|
+
let filename = (call.getString("name") ?? "screenshot")
|
16
|
+
DispatchQueue.main.async {
|
17
|
+
let config = WKSnapshotConfiguration()
|
18
|
+
config.rect = self.webView!.frame
|
19
|
+
config.afterScreenUpdates = false
|
20
|
+
self.webView?.takeSnapshot(with: config, completionHandler: {
|
21
|
+
(image: UIImage?, error: Error?) in
|
22
|
+
if error != nil {
|
23
|
+
return
|
24
|
+
}
|
25
|
+
guard let imageData = image!.jpegData(compressionQuality: quality) else {return}
|
26
|
+
let base64Result = imageData.base64EncodedString()
|
27
|
+
let file = "data:image/png;base64," + base64Result
|
28
|
+
|
29
|
+
var fileURI: URL = URL.init(fileURLWithPath: "")
|
30
|
+
do {
|
31
|
+
|
32
|
+
if #available(iOS 16.0, *) {
|
33
|
+
fileURI = URL(fileURLWithPath: filename+".png", relativeTo: .documentsDirectory)
|
34
|
+
} else {
|
35
|
+
// Fallback on earlier versions
|
36
|
+
fileURI = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathExtension(filename+".png")
|
37
|
+
}
|
38
|
+
try imageData.write(to: fileURI)
|
39
|
+
} catch {
|
40
|
+
// nothing to do
|
41
|
+
}
|
42
|
+
call.resolve([
|
43
|
+
"URI": fileURI.absoluteString,
|
44
|
+
"base64": file
|
45
|
+
])
|
46
|
+
})
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
6
|
+
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
7
|
+
<key>CFBundleExecutable</key>
|
8
|
+
<string>$(EXECUTABLE_NAME)</string>
|
9
|
+
<key>CFBundleIdentifier</key>
|
10
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
11
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
12
|
+
<string>6.0</string>
|
13
|
+
<key>CFBundleName</key>
|
14
|
+
<string>$(PRODUCT_NAME)</string>
|
15
|
+
<key>CFBundlePackageType</key>
|
16
|
+
<string>FMWK</string>
|
17
|
+
<key>CFBundleShortVersionString</key>
|
18
|
+
<string>1.0</string>
|
19
|
+
<key>CFBundleVersion</key>
|
20
|
+
<string>$(CURRENT_PROJECT_VERSION)</string>
|
21
|
+
<key>NSPrincipalClass</key>
|
22
|
+
<string></string>
|
23
|
+
</dict>
|
24
|
+
</plist>
|
package/package.json
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
{
|
2
|
+
"name": "@intuiface/capacitor-plugin-screenshot",
|
3
|
+
"version": "1.0.1",
|
4
|
+
"description": "Capacitor plugin to take screenshot for iOS and Android devices",
|
5
|
+
"main": "dist/plugin.cjs.js",
|
6
|
+
"module": "dist/esm/index.js",
|
7
|
+
"types": "dist/esm/index.d.ts",
|
8
|
+
"unpkg": "dist/plugin.js",
|
9
|
+
"files": [
|
10
|
+
"android/src/main/",
|
11
|
+
"android/build.gradle",
|
12
|
+
"dist/",
|
13
|
+
"ios/Plugin/",
|
14
|
+
"IntuifaceCapacitorPluginScreenshot.podspec"
|
15
|
+
],
|
16
|
+
"author": "intuiface",
|
17
|
+
"license": "MIT",
|
18
|
+
"repository": {
|
19
|
+
"type": "git",
|
20
|
+
"url": "git+https://github.com/intuiface/capacitor-plugin-screenshot.git"
|
21
|
+
},
|
22
|
+
"bugs": {
|
23
|
+
"url": "https://github.com/intuiface/capacitor-plugin-screenshot/issues"
|
24
|
+
},
|
25
|
+
"keywords": [
|
26
|
+
"capacitor",
|
27
|
+
"plugin",
|
28
|
+
"native"
|
29
|
+
],
|
30
|
+
"scripts": {
|
31
|
+
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
32
|
+
"verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..",
|
33
|
+
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
34
|
+
"verify:web": "npm run build",
|
35
|
+
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
36
|
+
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
37
|
+
"eslint": "eslint . --ext ts",
|
38
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
|
39
|
+
"swiftlint": "node-swiftlint",
|
40
|
+
"docgen": "docgen --api CapacitorScreenshotPlugin --output-readme README.md --output-json dist/docs.json",
|
41
|
+
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.js",
|
42
|
+
"clean": "rimraf ./dist",
|
43
|
+
"watch": "tsc --watch",
|
44
|
+
"prepublishOnly": "npm run build",
|
45
|
+
"prepare": "npx shx cp -u ./.githooks/* ./.git/hooks/"
|
46
|
+
},
|
47
|
+
"devDependencies": {
|
48
|
+
"@capacitor/android": "^5.0.0",
|
49
|
+
"@capacitor/core": "^5.0.0",
|
50
|
+
"@capacitor/docgen": "^0.0.18",
|
51
|
+
"@capacitor/ios": "^5.0.0",
|
52
|
+
"@ionic/eslint-config": "^0.3.0",
|
53
|
+
"@ionic/prettier-config": "^1.0.1",
|
54
|
+
"@ionic/swiftlint-config": "^1.1.2",
|
55
|
+
"eslint": "^7.11.0",
|
56
|
+
"prettier": "~2.3.0",
|
57
|
+
"prettier-plugin-java": "~1.0.2",
|
58
|
+
"rimraf": "^3.0.2",
|
59
|
+
"rollup": "^2.32.0",
|
60
|
+
"swiftlint": "^1.0.1",
|
61
|
+
"typescript": "~4.1.5"
|
62
|
+
},
|
63
|
+
"peerDependencies": {
|
64
|
+
"@capacitor/core": "^5.0.0"
|
65
|
+
},
|
66
|
+
"prettier": "@ionic/prettier-config",
|
67
|
+
"swiftlint": "@ionic/swiftlint-config",
|
68
|
+
"eslintConfig": {
|
69
|
+
"extends": "@ionic/eslint-config/recommended"
|
70
|
+
},
|
71
|
+
"capacitor": {
|
72
|
+
"ios": {
|
73
|
+
"src": "ios"
|
74
|
+
},
|
75
|
+
"android": {
|
76
|
+
"src": "android"
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|