Como posso capturar uma captura de tela de uma área selecionada da tela do telefone, não por nenhum programa, mas pelo código?
Como posso capturar uma captura de tela de uma área selecionada da tela do telefone, não por nenhum programa, mas pelo código?
Respostas:
Aqui está o código que permite que minha captura de tela seja armazenada em um cartão SD e usada posteriormente para quaisquer que sejam suas necessidades:
Primeiro, você precisa adicionar uma permissão adequada para salvar o arquivo:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
E este é o código (executando em uma atividade):
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();
}
}
E é assim que você pode abrir a imagem gerada recentemente:
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);
}
Se você deseja usar isso na exibição de fragmentos, use:
View v1 = getActivity().getWindow().getDecorView().getRootView();
ao invés de
View v1 = getWindow().getDecorView().getRootView();
na função takeScreenshot ()
Nota :
Esta solução não funciona se o seu diálogo contiver uma visualização de superfície. Para mais detalhes, verifique a resposta à seguinte pergunta:
Android Captura de tela da exibição em superfície mostra a tela preta
mCurrentUrlMask
deve ser uma View
vez que é a classe exclusiva na API do Android que possui o getRootView()
método Provavelmente é uma visão na interface do usuário.
View v1 = mCurrentUrlMask.getRootView();
eu usei View v1 = getWindow().getDecorView().getRootView();
e funciona para mim.
Chame esse método, passando o ViewGroup mais externo do qual você deseja uma captura de tela:
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()
como a visualização resulta em uma captura de tela apenas do aplicativo - não da tela.
Nota: funciona apenas para telefone enraizado
Programaticamente, você pode executar adb shell /system/bin/screencap -p /sdcard/img.png
como abaixo
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();
então leia img.png
como Bitmap
e use como desejar.
System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null
, meu dispositivo é o Android 5.0
EDIT: tenha piedade dos votos negativos. Era verdade em 2010, quando eu respondi a pergunta.
Todos os programas que permitem capturas de tela funcionam apenas em telefones com root.
Nenhuma permissão de raiz ou grande codificação é necessária para este método.
No shell adb, usando o comando abaixo, você pode capturar a tela.
input keyevent 120
Este comando não requer permissão de root, assim você também pode executar o código java do aplicativo Android.
Process process;
process = Runtime.getRuntime().exec("input keyevent 120");
Mais sobre o código do evento principal no Android, consulte http://developer.android.com/reference/android/view/KeyEvent.html
Aqui nós usamos. KEYCODE_SYSRQ seu valor é 120 e é usado para a chave Solicitação do sistema / Tela de impressão.
Como disse o CJBS, a imagem de saída será salva em / sdcard / Pictures / Screenshots
/sdcard/Pictures/Screenshots
su -c "input keyevent 120"
está bem !!
A resposta de Mualig é muito boa, mas eu tive o mesmo problema que Ewoks descreve, não estou entendendo nada. Às vezes, é bom o suficiente e às vezes recebo texto em preto sobre fundo preto (dependendo do tema).
Esta solução é fortemente baseada no código Mualig e no código que encontrei no Robotium. Estou descartando o uso do cache de desenho chamando diretamente para o método draw. Antes disso, tentarei extrair o plano de fundo da atividade atual para desenhá-lo primeiro.
// 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();
}
}
Adicione a permissão no manifesto
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Para suportar versões do Marshmallow ou superior, adicione o código abaixo na atividade onCreate method
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);
Como referência, uma maneira de capturar a tela (e não apenas a atividade do seu aplicativo) é capturar o buffer de quadros (dispositivo / dev / graphics / fb0). Para fazer isso, você deve ter privilégios de root ou seu aplicativo deve ser um aplicativo com permissões de assinatura ("Uma permissão que o sistema concede somente se o aplicativo solicitante for assinado com o mesmo certificado que o aplicativo que declarou a permissão") - que é muito improvável, a menos que você tenha compilado sua própria ROM.
Cada captura de buffer de quadros, de alguns dispositivos que testei, continha exatamente uma captura de tela. As pessoas relataram que ele contém mais, acho que depende do tamanho do quadro / tela.
Tentei ler o framebuffer continuamente, mas parece retornar uma quantidade fixa de bytes lidos. No meu caso, são (3 410 432) bytes, o suficiente para armazenar um quadro de exibição de 854 * 480 RGBA (3 279 360 bytes). Sim, o quadro, em binário, emitido a partir de fb0 é RGBA no meu dispositivo. Provavelmente, isso dependerá de dispositivo para dispositivo. Isso será importante para você decodificá-lo =)
No meu dispositivo / dev / graphics / fb0, as permissões são para que apenas o usuário root e os usuários dos gráficos do grupo possam ler o fb0.
graphics é um grupo restrito, portanto, você provavelmente só acessará o fb0 com um telefone root usando o comando su.
Os aplicativos Android têm o ID do usuário (uid) = app _ ## e o ID do grupo (guid) = app _ ## .
O shell adb possui uid = shell e guid = shell , que tem muito mais permissões que um aplicativo. Você pode realmente verificar essas permissões em /system/permissions/platform.xml
Isso significa que você poderá ler fb0 no shell adb sem raiz, mas não o lerá dentro do aplicativo sem raiz.
Além disso, conceder permissões READ_FRAME_BUFFER e / ou ACCESS_SURFACE_FLINGER no AndroidManifest.xml não fará nada para um aplicativo comum, porque elas só funcionarão para aplicativos de ' assinatura '.
Verifique também este tópico fechado para obter mais detalhes.
Minha solução é:
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;
}
e
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();
}
}
As imagens são salvas na pasta de armazenamento externo.
view
você está passando ImageUtils.loadBitmapFromView(this, view)
?
Você pode tentar a seguinte biblioteca: http://code.google.com/p/android-screenshot-library/ A Biblioteca de capturas de tela do Android (ASL) permite capturar programaticamente capturas de tela de dispositivos Android sem a necessidade de ter privilégios de acesso root. Em vez disso, o ASL utiliza um serviço nativo em execução em segundo plano, iniciado pelo Android Debug Bridge (ADB) uma vez por inicialização do dispositivo.
Com base na resposta de @JustinMorris acima e @NiravDangi aqui https://stackoverflow.com/a/8504958/2232148 , devemos pegar o plano de fundo e o primeiro plano de uma visualização e montá-los da seguinte forma:
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;
}
O parâmetro quality recebe uma constante de Bitmap.Config, normalmente 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();
}
}
ADICIONAR PERMISSÃO
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Você pode tentar fazer algo assim,
Obtendo um cache de bitmap a partir de um layout ou exibição, fazendo algo como Primeiro, você precisa setDrawingCacheEnabled
de um layout (um layout linear ou layout relativo ou uma exibição)
então
Bitmap bm = layout.getDrawingCache()
Então você faz o que quiser com o bitmap. Transforme-o em um arquivo de imagem ou envie a interface do usuário do bitmap para outro lugar.
Eu criei uma biblioteca simples que tira uma captura de tela de View
e fornece um objeto Bitmap ou salva diretamente em qualquer caminho que você desejar
Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath));
Como obter uma visão da atividade atual. Eu não quero usar o ID do xml.
takeScreenshotForScreen()
vez disso.
Caminho curto é
FrameLayout layDraw = (FrameLayout) findViewById(R.id.layDraw); /*Your root view to be part of screenshot*/
layDraw.buildDrawingCache();
Bitmap bmp = layDraw.getDrawingCache();
Apenas estendendo a resposta da taraloca. Você deve adicionar as seguintes linhas para fazê-lo funcionar. Eu fiz o nome da imagem estático. Certifique-se de usar a variável timestamp do taraloca, caso precise de um nome de imagem 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();
}
}
}
E no arquivo AndroidManifest.xml, as seguintes entradas são obrigatórias:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Se você quiser tirar uma captura de tela, fragment
siga este procedimento:
Substituir 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 captura de tela:
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 atividade, você pode simplesmente usar em View v1 = getWindow().getDecorView().getRootView();
vez demView
A maioria das respostas para esta pergunta usa o Canvas
método de desenho ou o cache de desenho. No entanto, o View.setDrawingCache()
método está obsoleto na API 28 . Atualmente, a API recomendada para fazer capturas de tela é a PixelCopy
classe disponível na API 24 (mas os métodos que aceitam Window
parâmetro estão disponíveis na API 26 == Android 8.0 Oreo). Aqui está um exemplo de código Kotlin para recuperar um 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
}
}
}
A visualização de parâmetro é o objeto de layout raiz.
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 captura de tela de rolagem de página inteira
Se você deseja capturar uma captura de tela completa do View (que contém uma visualização de rolagem ou mais), verifique esta biblioteca
Tudo o que você precisa fazer é importar o Gradel e criar um objeto do BigScreenshot
BigScreenshot longScreenshot = new BigScreenshot(this, x, y);
Um retorno de chamada será recebido com o bitmap das capturas de tela capturadas enquanto rolando automaticamente pelo grupo de exibição de tela e, no final, reunidos.
@Override public void getScreenshot(Bitmap bitmap) {}
Os quais podem ser salvos na galeria ou qualquer uso que seja necessário, após
Tire uma captura de tela de uma visualização no 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;
}
se você deseja capturar uma visualização ou layout como RelativeLayout ou LinearLayout etc., basta usar o código:
LinearLayout llMain = (LinearLayout) findViewById(R.id.linearlayoutMain);
Bitmap bm = loadBitmapFromView(llMain);
agora você pode salvar este bitmap no armazenamento do 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();}