Comment puis-je faire une capture d'écran d'une zone sélectionnée de l'écran du téléphone non pas par un programme mais à partir du code?
Comment puis-je faire une capture d'écran d'une zone sélectionnée de l'écran du téléphone non pas par un programme mais à partir du code?
Réponses:
Voici le code qui a permis à ma capture d'écran d'être stockée sur une carte SD et utilisée plus tard pour tous vos besoins:
Tout d'abord, vous devez ajouter une autorisation appropriée pour enregistrer le fichier:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Et voici le code (en cours d'exécution dans une activité):
private void takeScreenshot() {
Date now = new Date();
android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now);
try {
// image naming and path to include sd card appending name you choose for file
String mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpg";
// create bitmap screen capture
View v1 = getWindow().getDecorView().getRootView();
v1.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
File imageFile = new File(mPath);
FileOutputStream outputStream = new FileOutputStream(imageFile);
int quality = 100;
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
outputStream.flush();
outputStream.close();
openScreenshot(imageFile);
} catch (Throwable e) {
// Several error may come out with file handling or DOM
e.printStackTrace();
}
}
Et voici comment ouvrir l'image récemment générée:
private void openScreenshot(File imageFile) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(imageFile);
intent.setDataAndType(uri, "image/*");
startActivity(intent);
}
Si vous souhaitez l'utiliser sur la vue fragmentaire, utilisez:
View v1 = getActivity().getWindow().getDecorView().getRootView();
au lieu de
View v1 = getWindow().getDecorView().getRootView();
sur takeScreenshot () fonction
Remarque :
Cette solution ne fonctionne pas si votre boîte de dialogue contient une vue de surface. Pour plus de détails, veuillez vérifier la réponse à la question suivante:
Android Prendre une capture d'écran de Surface View montre un écran noir
mCurrentUrlMask
doit être un View
puisque c'est la classe unique dans l'API Android qui a la getRootView()
méthode. Est probablement une vue dans l'interface utilisateur.
View v1 = mCurrentUrlMask.getRootView();
j'ai utilisé View v1 = getWindow().getDecorView().getRootView();
et cela fonctionne pour moi.
Appelez cette méthode, en passant le groupe de vues externe le plus éloigné dont vous souhaitez une capture d'écran:
public Bitmap screenShot(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
view
? ''
getWindow().getDecorView().getRootView()
la vue, vous prenez une capture d'écran de l'application et non de l'écran.
Remarque: fonctionne uniquement pour les téléphones rootés
Par programme, vous pouvez exécuter adb shell /system/bin/screencap -p /sdcard/img.png
comme ci-dessous
Process sh = Runtime.getRuntime().exec("su", null,null);
OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII"));
os.flush();
os.close();
sh.waitFor();
puis lire img.png
comme Bitmap
et utiliser comme souhait.
System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null
, mon appareil est Android 5.0
EDIT: ayez pitié des downvotes. C'était vrai en 2010 lorsque j'ai répondu à la question.
Tous les programmes qui permettent les captures d'écran ne fonctionnent que sur les téléphones rootés.
Aucune autorisation root ou aucun grand codage n'est requis pour cette méthode.
Sur adb shell en utilisant la commande ci-dessous, vous pouvez prendre une capture d'écran.
input keyevent 120
Cette commande ne nécessite aucune autorisation root, donc vous pouvez également effectuer à partir du code java de l'application Android.
Process process;
process = Runtime.getRuntime().exec("input keyevent 120");
Pour en savoir plus sur le code d'événement clé dans Android, voir http://developer.android.com/reference/android/view/KeyEvent.html
Ici, nous avons utilisé. KEYCODE_SYSRQ sa valeur est 120 et utilisée pour la clé d'écran de demande / d'impression du système.
Comme l'a dit CJBS, l'image de sortie sera enregistrée dans / sdcard / Pictures / Screenshots
/sdcard/Pictures/Screenshots
su -c "input keyevent 120"
est ok !!
La réponse de Mualig est très bonne, mais j'ai eu le même problème que décrit Ewoks, je ne comprends pas l'arrière-plan. Donc, parfois c'est assez bien et parfois je reçois du texte noir sur fond noir (selon le thème).
Cette solution est fortement basée sur le code Mualig et le code que j'ai trouvé dans Robotium. J'écarte l'utilisation du cache de dessin en appelant directement la méthode draw. Avant cela, j'essaierai de tirer l'arrière-plan de l'activité en cours pour le dessiner en premier.
// Some constants
final static String SCREENSHOTS_LOCATIONS = Environment.getExternalStorageDirectory().toString() + "/screenshots/";
// Get device dimmensions
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
// Get root view
View view = mCurrentUrlMask.getRootView();
// Create the bitmap to use to draw the screenshot
final Bitmap bitmap = Bitmap.createBitmap(size.x, size.y, Bitmap.Config.ARGB_4444);
final Canvas canvas = new Canvas(bitmap);
// Get current theme to know which background to use
final Activity activity = getCurrentActivity();
final Theme theme = activity.getTheme();
final TypedArray ta = theme
.obtainStyledAttributes(new int[] { android.R.attr.windowBackground });
final int res = ta.getResourceId(0, 0);
final Drawable background = activity.getResources().getDrawable(res);
// Draw background
background.draw(canvas);
// Draw views
view.draw(canvas);
// Save the screenshot to the file system
FileOutputStream fos = null;
try {
final File sddir = new File(SCREENSHOTS_LOCATIONS);
if (!sddir.exists()) {
sddir.mkdirs();
}
fos = new FileOutputStream(SCREENSHOTS_LOCATIONS
+ System.currentTimeMillis() + ".jpg");
if (fos != null) {
if (!bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos)) {
Log.d(LOGTAG, "Compress/Write failed");
}
fos.flush();
fos.close();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
private void captureScreen() {
View v = getWindow().getDecorView().getRootView();
v.setDrawingCacheEnabled(true);
Bitmap bmp = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);
try {
FileOutputStream fos = new FileOutputStream(new File(Environment
.getExternalStorageDirectory().toString(), "SCREEN"
+ System.currentTimeMillis() + ".png"));
bmp.compress(CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Ajoutez l'autorisation dans le manifeste
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Pour prendre en charge Marshmallow ou les versions ci-dessus, veuillez ajouter le code ci-dessous dans la méthode d'activité onCreate
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);
À titre de référence, une façon de capturer l'écran (et pas seulement l'activité de votre application) est de capturer le framebuffer (device / dev / graphics / fb0). Pour ce faire, vous devez disposer des privilèges root ou votre application doit être une application avec des autorisations de signature ("Une autorisation que le système n'accorde que si l'application demandeuse est signée avec le même certificat que l'application qui a déclaré l'autorisation") - qui est très peu probable, sauf si vous avez compilé votre propre ROM.
Chaque capture de framebuffer, à partir de quelques appareils que j'ai testés, contenait exactement une capture d'écran. Les gens ont signalé qu'il contenait plus, je suppose que cela dépend de la taille du cadre / de l'affichage.
J'ai essayé de lire le framebuffer en continu, mais il semble revenir pour une quantité fixe d'octets lus. Dans mon cas, cela fait (3 410 432) octets, ce qui est suffisant pour stocker un cadre d'affichage de 854 * 480 RGBA (3 279 360 octets). Oui, le cadre, en binaire, sorti de fb0 est RGBA dans mon appareil. Cela dépendra très probablement d'un appareil à l'autre. Ce sera important pour vous de le décoder =)
Dans mon appareil / dev / graphics / fb0, les autorisations sont telles que seuls les utilisateurs root et de groupe peuvent lire le fb0.
les graphiques sont un groupe restreint, vous n'accéderez probablement à fb0 qu'avec un téléphone rooté en utilisant la commande su.
Les applications Android ont l' ID utilisateur (uid) = app _ ## et l' ID de groupe (guid) = app _ ## .
adb shell a uid = shell et guid = shell , qui a beaucoup plus d'autorisations qu'une application. Vous pouvez réellement vérifier ces autorisations dans /system/permissions/platform.xml
Cela signifie que vous pourrez lire fb0 dans le shell adb sans root mais vous ne le lirez pas dans l'application sans root.
En outre, l'octroi d'autorisations READ_FRAME_BUFFER et / ou ACCESS_SURFACE_FLINGER sur AndroidManifest.xml ne fera rien pour une application standard, car ceux-ci ne fonctionneront que pour les applications « signature ».
Consultez également ce fil fermé pour plus de détails.
Ma solution est:
public static Bitmap loadBitmapFromView(Context context, View v) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
v.measure(MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.EXACTLY));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Bitmap returnedBitmap = Bitmap.createBitmap(v.getMeasuredWidth(),
v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(returnedBitmap);
v.draw(c);
return returnedBitmap;
}
et
public void takeScreen() {
Bitmap bitmap = ImageUtils.loadBitmapFromView(this, view); //get Bitmap from the view
String mPath = Environment.getExternalStorageDirectory() + File.separator + "screen_" + System.currentTimeMillis() + ".jpeg";
File imageFile = new File(mPath);
OutputStream fout = null;
try {
fout = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fout);
fout.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
fout.close();
}
}
Les images sont enregistrées dans le dossier de stockage externe.
view
tu passes ImageUtils.loadBitmapFromView(this, view)
?
Vous pouvez essayer la bibliothèque suivante: http://code.google.com/p/android-screenshot-library/ La bibliothèque de captures d'écran Android (ASL) permet de capturer par programme des captures d'écran à partir d'appareils Android sans avoir besoin des privilèges d'accès root. Au lieu de cela, ASL utilise un service natif exécuté en arrière-plan, démarré via le pont de débogage Android (ADB) une fois par démarrage de l'appareil.
Sur la base de la réponse de @JustinMorris ci-dessus et @NiravDangi ici https://stackoverflow.com/a/8504958/2232148, nous devons prendre l'arrière-plan et le premier plan d'une vue et les assembler comme ceci:
public static Bitmap takeScreenshot(View view, Bitmap.Config quality) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), quality);
Canvas canvas = new Canvas(bitmap);
Drawable backgroundDrawable = view.getBackground();
if (backgroundDrawable != null) {
backgroundDrawable.draw(canvas);
} else {
canvas.drawColor(Color.WHITE);
}
view.draw(canvas);
return bitmap;
}
Le paramètre de qualité prend une constante de Bitmap.Config, généralement soit Bitmap.Config.RGB_565
ou Bitmap.Config.ARGB_8888
.
public class ScreenShotActivity extends Activity{
private RelativeLayout relativeLayout;
private Bitmap myBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
relativeLayout = (RelativeLayout)findViewById(R.id.relative1);
relativeLayout.post(new Runnable() {
public void run() {
//take screenshot
myBitmap = captureScreen(relativeLayout);
Toast.makeText(getApplicationContext(), "Screenshot captured..!", Toast.LENGTH_LONG).show();
try {
if(myBitmap!=null){
//save image to SD card
saveImage(myBitmap);
}
Toast.makeText(getApplicationContext(), "Screenshot saved..!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
public static Bitmap captureScreen(View v) {
Bitmap screenshot = null;
try {
if(v!=null) {
screenshot = Bitmap.createBitmap(v.getMeasuredWidth(),v.getMeasuredHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(screenshot);
v.draw(canvas);
}
}catch (Exception e){
Log.d("ScreenShotActivity", "Failed to capture screenshot because:" + e.getMessage());
}
return screenshot;
}
public static void saveImage(Bitmap bitmap) throws IOException{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 40, bytes);
File f = new File(Environment.getExternalStorageDirectory() + File.separator + "test.png");
f.createNewFile();
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
fo.close();
}
}
AJOUTER LA PERMISSION
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Vous pouvez essayer de faire quelque chose comme ça,
Obtenir un cache bitmap à partir d'une mise en page ou d'une vue en faisant quelque chose comme Premièrement, vous devez setDrawingCacheEnabled
accéder à une mise en page (une mise en page linéaire ou relative, ou une vue)
puis
Bitmap bm = layout.getDrawingCache()
Ensuite, vous faites ce que vous voulez avec le bitmap. Soit en le transformant en fichier image, soit en envoyant l'uri du bitmap ailleurs.
J'ai créé une bibliothèque simple qui prend une capture d'écran d'un View
et vous donne un objet Bitmap ou l'enregistre directement dans le chemin que vous voulez
Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath));
avez mentionné comment obtenir une vue de l'activité actuelle. Je ne veux pas utiliser l'identifiant du xml.
takeScreenshotForScreen()
place.
Le chemin est court
FrameLayout layDraw = (FrameLayout) findViewById(R.id.layDraw); /*Your root view to be part of screenshot*/
layDraw.buildDrawingCache();
Bitmap bmp = layDraw.getDrawingCache();
Je prolonge simplement la réponse de taraloca. Vous devez ajouter des lignes suivantes pour le faire fonctionner. J'ai rendu le nom de l'image statique. Veuillez vous assurer d'utiliser la variable d'horodatage de taraloca au cas où vous auriez besoin d'un nom d'image dynamique.
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private void verifyStoragePermissions() {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
}else{
takeScreenshot();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_EXTERNAL_STORAGE) {
takeScreenshot();
}
}
}
Et dans le fichier AndroidManifest.xml, les entrées suivantes doivent être:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Si vous souhaitez prendre une capture d'écran à partir fragment
de ce qui suit:
Remplacer onCreateView()
:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_one, container, false);
mView = view;
}
Logique pour prendre une capture d'écran:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
View view = mView.findViewById(R.id.scrollView1);
shareScreenShotM(view, (NestedScrollView) view);
}
méthode shareScreenShotM)()
:
public void shareScreenShotM(View view, NestedScrollView scrollView){
bm = takeScreenShot(view,scrollView); //method to take screenshot
File file = savePic(bm); // method to save screenshot in phone.
}
méthode takeScreenShot ():
public Bitmap takeScreenShot(View u, NestedScrollView z){
u.setDrawingCacheEnabled(true);
int totalHeight = z.getChildAt(0).getHeight();
int totalWidth = z.getChildAt(0).getWidth();
Log.d("yoheight",""+ totalHeight);
Log.d("yowidth",""+ totalWidth);
u.layout(0, 0, totalWidth, totalHeight);
u.buildDrawingCache();
Bitmap b = Bitmap.createBitmap(u.getDrawingCache());
u.setDrawingCacheEnabled(false);
u.destroyDrawingCache();
return b;
}
méthode savePic ():
public static File savePic(Bitmap bm){
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
File sdCardDirectory = new File(Environment.getExternalStorageDirectory() + "/Foldername");
if (!sdCardDirectory.exists()) {
sdCardDirectory.mkdirs();
}
// File file = new File(dir, fileName);
try {
file = new File(sdCardDirectory, Calendar.getInstance()
.getTimeInMillis() + ".jpg");
file.createNewFile();
new FileOutputStream(file).write(bytes.toByteArray());
Log.d("Fabsolute", "File Saved::--->" + file.getAbsolutePath());
Log.d("Sabsolute", "File Saved::--->" + sdCardDirectory.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
Pour l'activité, vous pouvez simplement utiliser View v1 = getWindow().getDecorView().getRootView();
au lieu demView
La plupart des réponses à cette question utilisent la Canvas
méthode de dessin ou la méthode de cache de dessin. Cependant, la View.setDrawingCache()
méthode est déconseillée dans l'API 28 . Actuellement, l'API recommandée pour faire des captures d'écran est la PixelCopy
classe disponible à partir de l'API 24 (mais les méthodes qui acceptent les Window
paramètres sont disponibles à partir de l'API 26 == Android 8.0 Oreo). Voici un exemple de code Kotlin pour récupérer un Bitmap
:
@RequiresApi(Build.VERSION_CODES.O)
fun saveScreenshot(view: View) {
val window = (view.context as Activity).window
if (window != null) {
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
val locationOfViewInWindow = IntArray(2)
view.getLocationInWindow(locationOfViewInWindow)
try {
PixelCopy.request(window, Rect(locationOfViewInWindow[0], locationOfViewInWindow[1], locationOfViewInWindow[0] + view.width, locationOfViewInWindow[1] + view.height), bitmap, { copyResult ->
if (copyResult == PixelCopy.SUCCESS) {
saveBitmap(bitmap)
}
// possible to handle other result codes ...
}, Handler())
} catch (e: IllegalArgumentException) {
// PixelCopy may throw IllegalArgumentException, make sure to handle it
}
}
}
La vue des paramètres est l'objet de présentation racine.
public static Bitmap screenShot(View view) {
Bitmap bitmap = null;
if (view.getWidth() > 0 && view.getHeight() > 0) {
bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
}
return bitmap;
}
Pour une capture d'écran de défilement pleine page
Si vous souhaitez capturer une capture d'écran de vue complète (qui contient une vue de défilement), vérifiez cette bibliothèque
Tout ce que vous avez à faire est d'importer le Gradel et de créer un objet de BigScreenshot
BigScreenshot longScreenshot = new BigScreenshot(this, x, y);
Un rappel sera reçu avec le bitmap des captures d'écran prises tout en faisant défiler automatiquement le groupe de vues d'écran et à la fin assemblées ensemble.
@Override public void getScreenshot(Bitmap bitmap) {}
Qui peut être enregistré dans la galerie ou quelle que soit l'utilisation est nécessaire leur après
Prenez une capture d'écran d'une vue dans Android.
public static Bitmap getViewBitmap(View v) {
v.clearFocus();
v.setPressed(false);
boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
if (color != 0) {
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null) {
return null;
}
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
return bitmap;
}
si vous voulez capturer une vue ou une mise en page comme RelativeLayout ou LinearLayout etc. utilisez simplement le code:
LinearLayout llMain = (LinearLayout) findViewById(R.id.linearlayoutMain);
Bitmap bm = loadBitmapFromView(llMain);
vous pouvez maintenant enregistrer ce bitmap sur le stockage de l'appareil en:
FileOutputStream outStream = null;
File f=new File(Environment.getExternalStorageDirectory()+"/Screen Shots/");
f.mkdir();
String extStorageDirectory = f.toString();
File file = new File(extStorageDirectory, "my new screen shot");
pathOfImage = file.getAbsolutePath();
try {
outStream = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
Toast.makeText(getApplicationContext(), "Saved at "+f.getAbsolutePath(), Toast.LENGTH_LONG).show();
addImageGallery(file);
//mail.setEnabled(true);
flag=true;
} catch (FileNotFoundException e) {e.printStackTrace();}
try {
outStream.flush();
outStream.close();
} catch (IOException e) {e.printStackTrace();}