Comment faire une capture d'écran par programmation sur Android?

495

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?

korovaisdead
la source
4
Pas d'émulateur. J'ai besoin de faire une capture d'écran d'une partie de mon programme et de le faire dans le même programme.
korovaisdead
1
Une autre bonne référence: stackoverflow.com/a/10296881/439171
Italo Borssatto

Réponses:

448

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

taraloca
la source
23
Salut, pouvez-vous décrire ce qu'est mCurrentUrlMask? J'ai essayé ce code mais il me donne toujours NullPointerException à Bitmap.createBitmap (v1.getDrawingCache ()), quelqu'un peut-il dire ce que je fais mal.? Toute aide est appréciée. Merci.
Mitesh Sardhara du
4
@MiteshSardhara mCurrentUrlMaskdoit être un Viewpuisque c'est la classe unique dans l'API Android qui a la getRootView()méthode. Est probablement une vue dans l'interface utilisateur.
gipi
6
Pouvez-vous me dire ce que c'est, mCurrentUrlMask?
Jayeshkumar Sojitra
37
Insted de View v1 = mCurrentUrlMask.getRootView();j'ai utilisé View v1 = getWindow().getDecorView().getRootView();et cela fonctionne pour moi.
enadun
9
Cette réponse prend une capture d'écran de l'application uniquement - pas de "l'écran du téléphone" comme demandé dans la question - ou est-ce que je fais quelque chose de mal.
AlikElzin-kilaka
126

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;
}
JustinMorris
la source
9
Cela semble être un code plus propre que la réponse acceptée. Fonctionne-t-il aussi bien?
jophde
2
Je l'ai utilisé pendant un certain temps dans plusieurs applications différentes et je n'ai eu aucun problème.
JustinMorris
3
Si vous voulez obtenir une capture d'écran du téléphone, où votre application est en arrière-plan, que passez-vous comme view? ''
AlikElzin-kilaka
2
Si vous passez getWindow().getDecorView().getRootView()la vue, vous prenez une capture d'écran de l'application et non de l'écran.
AlikElzin-kilaka
Cette réponse prend une capture d'écran de l'application uniquement - pas de "l'écran du téléphone" comme demandé dans la question - ou est-ce que je fais quelque chose de mal.
AlikElzin-kilaka
42

Remarque: fonctionne uniquement pour les téléphones rootés

Par programme, vous pouvez exécuter adb shell /system/bin/screencap -p /sdcard/img.pngcomme 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.pngcomme Bitmapet utiliser comme souhait.

Viswanath Lekshmanan
la source
A-t-il besoin d'un accès root?
zoom
3
Oui, vous avez besoin d'un accès root. Veuillez vérifier la note à la rubrique
Viswanath Lekshmanan
Salut, j'en ai un System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null , mon appareil est Android 5.0
Eddy
@Eddy Cela dépend de votre appareil
Demian
Existe-t-il un moyen de lire directement la sortie sans enregistrer le résultat dans un fichier, puis le relire? stackoverflow.com/questions/43914035
Yazan W Yusuf
35

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.

RDA
la source
Il semble que ces jours-ci, c'est possible sur Androids avec un chipset basé sur Tegra
GDR
4.0.3 - alors c'est probablement l'une de ces tablettes tegra new-school
RDA
AFAIK lorsque les appareils ont une application stock pour capturer des captures d'écran, c'est une application avec des privilèges de signature spéciaux qui lui permettent de capturer le framebuffer (un tampon avec contient les pixels de l'écran). Il est donc vrai que si votre ROM possède une telle application, vous n'aurez pas besoin d'être rooté, mais seule cette application peut faire des captures, pas la vôtre.
Rui Marques
2
Strictement parlant, avec le compte utilisateur "shell" de root ADB, il a toujours été autorisé à le faire car c'était le cas d'utilisation prévu. Ce qui n'était pas disponible historiquement (sauf sur les builds occasionnels comme une erreur) était un moyen pour les ID utilisateur de l' application de le faire.
Chris Stratton
26

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

Jeegar Patel
la source
L'image de sortie sera enregistrée ici:/sdcard/Pictures/Screenshots
CJBS
faut-il une autorisation root ??
Taranmeet Singh
1
ça va marcher sur la guimauve? ou cela fonctionnera-t-il en arrière-plan de service @JeegarPatel
karanatwal.github.io
2
ne fonctionnait pas par programme, mais fonctionne à partir du shell. Essayé avec du nougat.
mehmet6parmak
1
su -c "input keyevent 120"est ok !!
ipcjs
17

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();
}
xamar
la source
J'ai une liste avec android: cacheColorHint = "# 00000000" dans mon activité, et j'utilise ce code pour faire une capture d'écran, j'ai toujours un fond noir, car j'ai trouvé que l'arrière-plan qui provient du thème est noir, comment puis-je gérer cela listview?
Wangchao0721
Activity activité = getCurrentActivity donnant une méthode non définie à Eroor.
Shabbir Dhangot
17
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);
Crazy Coder
la source
Nécessite: <uses-permission android: name = "android.permission.WRITE_EXTERNAL_STORAGE" />
AndroidGuy
4
Cette réponse prend une capture d'écran de l'application uniquement - pas de "l'écran du téléphone" comme demandé dans la question - ou est-ce que je fais quelque chose de mal?
AlikElzin-kilaka
Et si j'ai besoin d'une capture d'écran d'un élément de la liste?
Anshul Tyagi
je veux capturer à partir de l'adaptateur une idée comment puis-je le faire?
Deep Dave
16

À 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.

Rui Marques
la source
2
Cela fonctionne (a fonctionné?) Sur certains téléphones, mais notez que les téléphones basés sur GPU ne fournissent pas nécessairement un framebuffer linéaire au processeur d'applications.
Chris Stratton
15

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.

validcat
la source
1
Vous devez fermer FileOutputStream dans un bloc finally. Si vous rencontrez une exception maintenant, le flux ne sera pas fermé.
Wotuu
À quoi viewtu passes ImageUtils.loadBitmapFromView(this, view)?
AlikElzin-kilaka
1
pourquoi utilisez-vous v.layout (0, 0, v.getMeasuredWidth (), v.getMeasuredHeight ()); ? Cela ne change-t-il pas la vue (v)?
serj
11

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.

Kuba
la source
1
J'ai essayé, mais il suffit de prendre une capture d'écran de l'application en cours d'exécution. Son ne peux pas aider si je veux prendre une capture d'écran de l'écran d'accueil. comment faire une capture d'écran de l'écran d'accueil avec ce code?
Jana
1
@ Janardhanan.S: C'est ce que la question demande. Pouvez-vous élaborer avec une nouvelle réponse au lieu de poser une question distincte.
trgraglia
3
Même problème avec moi .. "Le service natif ne fonctionne pas !!"
Yogesh Maheshwari
1
Même chose avec moi "Le service natif ne fonctionne pas !!" .... quelqu'un peut-il ajouter le texte d'aide ici?
Pankaj Kumar
1
pareil ici! "Le service natif ne fonctionne pas !!" et dans leur dernière version 1.2, ils utilisent des classes API LEVEL 19, comme Socket par exemple.
user347187
10

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_565ou Bitmap.Config.ARGB_8888.

Oliver Hausler
la source
dessiner une toile de couleur blanche au cas où l'arrière-plan est nul a fait l'affaire pour moi. Merci Oliver
Shaleen
8
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"/>
Vaishali Sutariya
la source
Cette réponse prend une capture d'écran de l'application uniquement - pas de "l'écran du téléphone" comme demandé dans la question - ou est-ce que je fais quelque chose de mal?
AlikElzin-kilaka
7

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 setDrawingCacheEnabledaccé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.

Kevin Tan
la source
1
C'est la meilleure méthode si c'est votre application que vous écrivez sur un bitmap. Méfiez-vous également des méthodes qui ont des retards avant de prendre le cache ... comme Notify ... () pour les vues de liste.
trgraglia
Pas seulement ça. La mise en page doit d'abord être affichée à l'écran. C'est le "cache" que vous obtenez après tout. J'ai essayé de cacher la vue et de prendre des captures d'écran en arrière-plan (en théorie), mais cela n'a pas fonctionné.
Kevin Tan
De loin plus efficace que les autres solutions
sivi
6

Pour ceux qui veulent capturer une GLSurfaceView, la méthode getDrawingCache ou le dessin sur toile ne fonctionnera pas.

Vous devez lire le contenu du framebuffer OpenGL après le rendu du cadre. Il y a une bonne réponse ici

rockeye
la source
6

J'ai créé une bibliothèque simple qui prend une capture d'écran d'un Viewet vous donne un objet Bitmap ou l'enregistre directement dans le chemin que vous voulez

https://github.com/abdallahalaraby/Blink

Abdallah Alaraby
la source
Faut-il un téléphone rooté?
Nilesh Agrawal
1
Aucun enracinement requis :)
Abdallah Alaraby
En utilisation, vous 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.
Nilesh Agrawal
utiliser à la takeScreenshotForScreen()place.
Abdallah Alaraby
6

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();
Chintan Khetiya
la source
5

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" />
TechBee
la source
4

Si vous souhaitez prendre une capture d'écran à partir fragment de ce qui suit:

  1. 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;
            }
  2. 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); 
     }
  3. 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.
        }
  4. 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;
            }
  5. 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

Parsania Hardik
la source
3

La plupart des réponses à cette question utilisent la Canvasmé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 PixelCopyclasse disponible à partir de l'API 24 (mais les méthodes qui acceptent les Windowparamè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
        }
    }
}
Miloš Černilovský
la source
Le problème avec PixelCopy sur la solution drawingCache est qu'il semble ne capturer que les pixels visibles. le reste est noir pour moi. Il n'est donc pas possible de partager des éléments qui défilent et sont en partie hors du cadre. Avez-vous une solution à cela?
Henning
Tu as raison. De même, cela peut causer un problème si une autre vue est affichée au-dessus de la vue que je veux faire une capture d'écran (par exemple lorsque le tiroir est ouvert). Dans ces cas, j'utilise simplement l'ancienne méthode Canvas :(
Miloš Černilovský
1
Est-il possible de prendre une capture d'écran sur n'importe quelle application en cours d'exécution à l'aide de PixelCopy?
Amir Rezaei
2

Pour les applications système uniquement!

Process process;
process = Runtime.getRuntime().exec("screencap -p " + outputPath);
process.waitFor();

Remarque: les applications système n'ont pas besoin d'exécuter "su" pour exécuter cette commande.

GilCol
la source
2

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;
                }
Anil Singhania
la source
2

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

https://github.com/peter1492/LongScreenshot

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

Peter
la source
1

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;
}
Mohit Singh
la source
-1

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();}
Akshay Paliwal
la source