¿Cómo puedo tomar una captura de pantalla de un área seleccionada de la pantalla del teléfono no mediante ningún programa sino desde el código?
¿Cómo puedo tomar una captura de pantalla de un área seleccionada de la pantalla del teléfono no mediante ningún programa sino desde el código?
Respuestas:
Aquí está el código que permitió que mi captura de pantalla se almacenara en una tarjeta SD y se usara más tarde para lo que sea que necesite:
Primero, debe agregar un permiso adecuado para guardar el archivo:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Y este es el código (que se ejecuta en una Actividad):
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();
}
}
Y así es como puede abrir la imagen generada recientemente:
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 desea usar esto en la vista de fragmentos, use:
View v1 = getActivity().getWindow().getDecorView().getRootView();
en vez de
View v1 = getWindow().getDecorView().getRootView();
en takeScreenshot () función
Nota :
Esta solución no funciona si su cuadro de diálogo contiene una vista de superficie. Para más detalles, consulte la respuesta a la siguiente pregunta:
Captura de pantalla de Android Take de Surface View muestra pantalla en negro
mCurrentUrlMask
debe ser una View
clase única en la API de Android que tiene el getRootView()
método. Probablemente es una vista en la interfaz de usuario.
View v1 = mCurrentUrlMask.getRootView();
que he utilizado View v1 = getWindow().getDecorView().getRootView();
y funciona para mí.
Llame a este método, pasando el ViewGroup más externo del que desea una captura de pantalla:
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 vista da como resultado una captura de pantalla de la aplicación, no de la pantalla.
Nota: funciona solo para teléfonos rooteados
Programáticamente, puede ejecutar adb shell /system/bin/screencap -p /sdcard/img.png
como a continuación
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();
luego lea img.png
como Bitmap
y use como desee.
System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null
, mi dispositivo es Android 5.0
EDITAR: ten piedad de los votos negativos. Fue cierto en 2010 cuando respondí la pregunta.
Todos los programas que permiten capturas de pantalla solo funcionan en teléfonos rooteados.
No se requiere permiso de root o no se requiere una gran codificación para este método.
En adb shell con el siguiente comando, puede tomar una captura de pantalla.
input keyevent 120
Este comando no requiere ningún permiso de root, por lo que también puede realizarlo desde el código Java de la aplicación de Android.
Process process;
process = Runtime.getRuntime().exec("input keyevent 120");
Más información sobre el código Keyevent en Android, consulte http://developer.android.com/reference/android/view/KeyEvent.html
Aquí lo hemos usado. KEYCODE_SYSRQ su valor es 120 y se utiliza para la tecla Solicitud del sistema / Imprimir pantalla.
Como dijo CJBS, la imagen de salida se guardará en / sdcard / Pictures / Screenshots
/sdcard/Pictures/Screenshots
su -c "input keyevent 120"
esta bien !!
La respuesta de Mualig es muy buena, pero tuve el mismo problema que describe Ewoks, no entiendo el fondo. Entonces, a veces es lo suficientemente bueno y a veces obtengo texto negro sobre fondo negro (dependiendo del tema).
Esta solución está fuertemente basada en el código Mualig y el código que encontré en Robotium. Estoy descartando el uso de la memoria caché de dibujo llamando directamente al método de dibujo. Antes de eso, trataré de dibujar el fondo de la actividad actual para dibujarlo primero.
// 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();
}
}
Agregue el permiso en el manifiesto
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Para admitir Marshmallow o versiones superiores, agregue el siguiente código en la actividad del método Crear
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);
Como referencia, una forma de capturar la pantalla (y no solo la actividad de su aplicación) es capturar el framebuffer (dispositivo / dev / graphics / fb0). Para hacer esto, debe tener privilegios de root o su aplicación debe ser una aplicación con permisos de firma ("Un permiso que el sistema otorga solo si la aplicación solicitante está firmada con el mismo certificado que la aplicación que declaró el permiso"), que es muy poco probable a menos que haya compilado su propia ROM.
Cada captura de framebuffer, de un par de dispositivos que he probado, contenía exactamente una captura de pantalla. La gente ha informado que contiene más, supongo que depende del tamaño del marco / pantalla.
Traté de leer el framebuffer continuamente, pero parece volver por una cantidad fija de bytes leídos. En mi caso, eso es (3 410 432) bytes, que es suficiente para almacenar un marco de visualización de 854 * 480 RGBA (3 279 360 bytes). Sí, el marco, en binario, generado desde fb0 es RGBA en mi dispositivo. Esto probablemente dependerá de un dispositivo a otro. Esto será importante para que lo decodifiques =)
En mi dispositivo / dev / graphics / fb0 los permisos son para que solo la raíz y los usuarios de los gráficos de grupo puedan leer el fb0.
graphics es un grupo restringido, por lo que probablemente solo accederá a fb0 con un teléfono rooteado mediante el comando su.
Las aplicaciones de Android tienen la identificación de usuario (uid) = aplicación _ ## y la identificación de grupo (guid) = aplicación _ ## .
adb shell tiene uid = shell y guid = shell , que tiene muchos más permisos que una aplicación. En realidad, puede verificar esos permisos en /system/permissions/platform.xml
Esto significa que podrá leer fb0 en el shell adb sin root, pero no lo leerá dentro de la aplicación sin root.
Además, otorgar permisos READ_FRAME_BUFFER y / o ACCESS_SURFACE_FLINGER en AndroidManifest.xml no hará nada para una aplicación normal porque solo funcionará para aplicaciones de ' firma '.
También revise este hilo cerrado para más detalles.
Mi solución es:
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;
}
y
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();
}
}
Las imágenes se guardan en la carpeta de almacenamiento externo.
view
qué estás pasando ImageUtils.loadBitmapFromView(this, view)
?
Puede probar la siguiente biblioteca: http://code.google.com/p/android-screenshot-library/ Android Screenshot Library (ASL) permite capturar capturas de pantalla mediante programación de dispositivos Android sin necesidad de tener privilegios de acceso a la raíz. En cambio, ASL utiliza un servicio nativo que se ejecuta en segundo plano, iniciado a través del Android Debug Bridge (ADB) una vez por inicio de dispositivo.
Según la respuesta de @JustinMorris arriba y @NiravDangi aquí https://stackoverflow.com/a/8504958/2232148 debemos tomar el fondo y el primer plano de una vista y ensamblarlos así:
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;
}
El parámetro de calidad toma una constante de Bitmap.Config, normalmente Bitmap.Config.RGB_565
o 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();
}
}
AGREGAR PERMISO
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Puedes intentar hacer algo como esto,
Obtener un caché de mapa de bits de un diseño o una vista haciendo algo como Primero, setDrawingCacheEnabled
debe obtener un diseño (un diseño lineal o un diseño relativo, o una vista)
entonces
Bitmap bm = layout.getDrawingCache()
Luego haces lo que quieras con el mapa de bits. Ya sea convirtiéndolo en un archivo de imagen o enviando la uri del mapa de bits a otro lugar.
He creado una biblioteca simple que toma una captura de pantalla de a View
y le da un objeto de mapa de bits o lo guarda directamente en cualquier ruta que desee
Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath));
Cómo obtener una vista de la actividad actual. No quiero usar la identificación del xml.
takeScreenshotForScreen()
en su lugar.
Camino corto es
FrameLayout layDraw = (FrameLayout) findViewById(R.id.layDraw); /*Your root view to be part of screenshot*/
layDraw.buildDrawingCache();
Bitmap bmp = layDraw.getDrawingCache();
Solo extendiendo la respuesta de taraloca. Debe agregar las siguientes líneas para que funcione. He hecho que el nombre de la imagen sea estático. Asegúrese de utilizar la variable de marca de tiempo de taraloca en caso de que necesite un nombre de imagen dinámico.
// 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();
}
}
}
Y en el archivo AndroidManifest.xml las siguientes entradas son obligatorias:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Si desea tomar una captura de pantalla, fragment
siga esto:
Anular 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;
}
Lógica para tomar captura de pantalla:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
View view = mView.findViewById(R.id.scrollView1);
shareScreenShotM(view, (NestedScrollView) view);
}
método 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étodo 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étodo 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;
}
Para la actividad, simplemente puede usar en View v1 = getWindow().getDecorView().getRootView();
lugar demView
La mayoría de las respuestas a esta pregunta utilizan el Canvas
método de dibujo o el método de caché de dibujo. Sin embargo, el View.setDrawingCache()
método está en desuso en la API 28 . Actualmente, la API recomendada para hacer capturas de pantalla es la PixelCopy
clase disponible en API 24 (pero los métodos que aceptan Window
parámetros están disponibles en API 26 == Android 8.0 Oreo). Aquí hay un ejemplo de código de Kotlin para recuperar 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 vista de parámetros es el objeto de diseño raíz.
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;
}
Para la captura de pantalla de desplazamiento de página completa
Si desea capturar una captura de pantalla de Vista completa (que contiene una vista de desplazamiento más o menos), consulte esta biblioteca
Todo lo que tiene que hacer es importar Gradel y crear un objeto de BigScreenshot
BigScreenshot longScreenshot = new BigScreenshot(this, x, y);
Se recibirá una devolución de llamada con el mapa de bits de las Capturas de pantalla tomadas mientras se desplaza automáticamente a través del grupo de visualización de pantalla y al final se ensamblan.
@Override public void getScreenshot(Bitmap bitmap) {}
Lo que se puede guardar en la galería o cualquier uso es necesario después de
Tome una captura de pantalla de una vista en 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 desea capturar una vista o diseño como RelativeLayout o LinearLayout, etc., simplemente use el código:
LinearLayout llMain = (LinearLayout) findViewById(R.id.linearlayoutMain);
Bitmap bm = loadBitmapFromView(llMain);
ahora puede guardar este mapa de bits en el almacenamiento del dispositivo:
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();}