Як я можу зробити знімок екрана вибраної області екрану телефону не будь-якою програмою, а кодом?
Як я можу зробити знімок екрана вибраної області екрану телефону не будь-якою програмою, а кодом?
Відповіді:
Ось код, який дозволив моєму скріншоті зберігатись на SD-картці та використовувати його згодом для будь-яких потреб:
Спочатку потрібно додати належний дозвіл на збереження файлу:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
А це код (працює в діяльності):
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();
}
}
Ось так ви можете відкрити нещодавно створене зображення:
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);
}
Якщо ви хочете використовувати це на перегляді фрагментів, тоді використовуйте:
View v1 = getActivity().getWindow().getDecorView().getRootView();
замість
View v1 = getWindow().getDecorView().getRootView();
на takeScreenshot () функція
Примітка :
Це рішення не працює, якщо діалогове вікно містить вид поверхні. Щоб отримати детальну інформацію, перегляньте відповідь на наступне питання:
mCurrentUrlMask
повинен бути View
унікальним класом в Android API, який має getRootView()
метод. Ймовірно, це погляд в інтерфейсі.
View v1 = mCurrentUrlMask.getRootView();
I використовував View v1 = getWindow().getDecorView().getRootView();
і це працює для мене.
Зателефонуйте цьому методу, перейшовши у зовнішню найбільшу ViewGroup, яку ви бажаєте зняти на екрані:
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()
як результат, ви робите знімок екрана лише програми - не екрана.
Примітка: працює лише для вкоріненого телефону
Програмно можна запустити, adb shell /system/bin/screencap -p /sdcard/img.png
як показано нижче
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();
потім читайте img.png
як Bitmap
і використовуйте як своє бажання.
System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null
, мій пристрій андроїд 5.0
РЕДАКТУЙ: помилуйсь з низовими записами. Це було правдою в 2010 році, коли я відповів на питання.
Усі програми, які дозволяють знімати екрани, працюють лише на вкорінених телефонах.
Ніякого кореневого дозволу або великого кодування для цього методу не потрібно.
У оболонці adb за допомогою команди нижче можна зробити знімок екрана.
input keyevent 120
Ця команда не вимагає дозволу root, тому те саме ви можете виконувати і з java-коду програми Android.
Process process;
process = Runtime.getRuntime().exec("input keyevent 120");
Детальніше про код keyevent в android див. На http://developer.android.com/reference/android/view/KeyEvent.html
Ось ми і використали. KEYCODE_SYSRQ його значення дорівнює 120 і використовується для клавіші екранного запиту / друку.
Як сказав CJBS, вихідне зображення буде збережено в / sdcard / Pictures / Screenshots
/sdcard/Pictures/Screenshots
su -c "input keyevent 120"
нормально !!
Відповідь Муаліга дуже хороша, але у мене була та сама проблема, яку описує Евокс, я не отримую передумови. Тому іноді досить добре, а іноді я отримую чорний текст на чорному тлі (залежно від теми).
Це рішення базується на коді Муаліга та коді, який я знайшов у Robotium. Я відкидаю використання кешу малювання, зателефонувавши безпосередньо до методу малювання. Перед цим я спробую зробити фон, який можна зрозуміти з поточної діяльності, щоб намалювати його першим.
// 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();
}
}
Додайте дозвіл у маніфест
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Для підтримки Marshmallow або вище версій, будь ласка, додайте наведений нижче код в активі onCreate метод
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);
В якості довідки, один із способів захоплення екрана (а не лише активності вашої програми) - це захоплення фреймбуфера (device / dev / graphics / fb0). Для цього у вас повинні бути або root права, або ваш додаток повинен мати додаток з дозволом на підпис ("Дозвіл, який система надає лише у тому випадку, якщо запитуючий додаток підписаний тим самим сертифікатом, що і додаток, який оголосив дозвіл") - який дуже малоймовірно, якщо ви не склали власний ПЗУ.
Кожен знімок кадрів з декількох пристроїв, які я перевірив, містив рівно один знімок екрана. Люди повідомили, що вона містить більше, я думаю, це залежить від розміру кадру / дисплея.
Я намагався читати фреймбуфер постійно, але, схоже, повертається за фіксовану кількість прочитаних байтів. У моєму випадку це (3 410 432) байтів, що достатньо для зберігання кадру відображення розміром 854 * 480 RGBA (3 279 360 байт). Так, кадр у двійковій формі, що виводиться з fb0, є RGBA на моєму пристрої. Це, швидше за все, буде залежати від пристрою до пристрою. Це буде важливо для вас, щоб розшифрувати його =)
У моєму пристрої / dev / graphics / fb0 дозволи дозволяють читати fb0 лише root та користувачі з групової графіки.
графіка є групою з обмеженим доступом, тому ви, ймовірно, можете отримати доступ до fb0 тільки з вкоріненим телефоном за допомогою команди su.
У додатках для Android є ідентифікатор користувача (uid) = app _ ## та ідентифікатор групи (guide) = app _ ## .
adb shell має uid = shell та guide = оболонку , що має набагато більше дозволів, ніж програма. Ви можете перевірити ці дозволи на /system/permissions/platform.xml
Це означає, що ви зможете читати fb0 в оболонці adb без кореня, але ви не будете читати його в додатку без кореня.
Крім того, надання дозволів READ_FRAME_BUFFER та / або ACCESS_SURFACE_FLINGER на AndroidManifest.xml не буде нічого робити для звичайного додатка, оскільки вони працюватимуть лише для програм " підпису ".
Також перевірте цю закриту нитку для отримання більш детальної інформації.
Моє рішення:
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;
}
і
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();
}
}
Зображення зберігаються у зовнішній папці зберігання.
view
ти переходиш ImageUtils.loadBitmapFromView(this, view)
?
Можна спробувати наступну бібліотеку: http://code.google.com/p/android-screenshot-library/ Бібліотека екрана екрана Android (ASL) дозволяє програматично знімати знімки екрана з пристроїв Android, не вимагаючи привілеїв кореневого доступу. Натомість ASL використовує вбудований сервіс, який працює у фоновому режимі, запускається через міст налагодження Android (ADB) один раз на завантаження пристрою.
Виходячи з відповіді @JustinMorris та @NiravDangi тут https://stackoverflow.com/a/8504958/2232148, ми повинні взяти тло та передній план подання та зібрати їх так:
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;
}
Параметр якості приймає константу Bitmap.Config, як правило, Bitmap.Config.RGB_565
або 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();
}
}
ДОДАТИ ДОГОВІР
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Ви можете спробувати зробити щось подібне,
Отримання кеш- setDrawingCacheEnabled
файлу растрового зображення з макета чи перегляду, виконуючи щось на кшталт Спочатку вам доведеться створити макет (лінійний розміщення або відносний розміщення або вигляд)
тоді
Bitmap bm = layout.getDrawingCache()
Тоді ви робите все, що забажаєте, з растровою картою. Або перетворивши його у файл зображення, або надішліть урі растрової карти кудись ще.
Я створив просту бібліотеку, яка знімає знімок екрана з View
і дає вам об'єкт Bitmap або зберігає його безпосередньо на будь- який потрібний вам шлях
Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath));
Як переглянути перегляд поточної активності. Я не хочу використовувати ідентифікатор xml.
takeScreenshotForScreen()
замість цього.
Короткий шлях є
FrameLayout layDraw = (FrameLayout) findViewById(R.id.layDraw); /*Your root view to be part of screenshot*/
layDraw.buildDrawingCache();
Bitmap bmp = layDraw.getDrawingCache();
Просто продовження відповіді таралоки. Ви повинні додати наступні рядки, щоб це працювало. Я зробив ім'я зображення статичним. Будь ласка, переконайтеся, що ви використовуєте змінну часової позначки таралоки, якщо вам потрібна назва динамічного зображення.
// 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();
}
}
}
А у файлі AndroidManifest.xml необхідні такі записи:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Якщо ви хочете зробити знімок екрана, fragment
ніж слід, виконайте це:
Заміна 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;
}
Логіка створення знімка екрана:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
View view = mView.findViewById(R.id.scrollView1);
shareScreenShotM(view, (NestedScrollView) view);
}
метод 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.
}
метод 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;
}
метод 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;
}
Для діяльності ви можете просто використовувати View v1 = getWindow().getDecorView().getRootView();
замість цьогоmView
Більшість відповідей на це питання використовують Canvas
метод малювання або метод кешу малювання. Однак View.setDrawingCache()
метод застарілий в API 28 . В даний час рекомендованим API для створення скріншотів є PixelCopy
клас, доступний в API 24 (але методи, які приймають Window
параметр, доступні в API 26 == Android 8.0 Oreo). Ось зразок котла Котліна для отримання 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
}
}
}
Перегляд параметра - це об'єкт кореневого макета.
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;
}
Знімок екрана прокрутки на повній сторінці
Якщо ви хочете зробити повний знімок екрана View (який містить перегляд прокрутки чи так), тоді перевірте цю бібліотеку
Все, що вам потрібно зробити, це імпортувати Градель і створити об’єкт BigScreenshot
BigScreenshot longScreenshot = new BigScreenshot(this, x, y);
Зворотний виклик буде отриманий із растровою екраном знімків екрана, зробленою під час автоматичної прокрутки групи перегляду екрана та наприкінці зібраної разом.
@Override public void getScreenshot(Bitmap bitmap) {}
Які можна зберегти в галереї або будь-яке використання, необхідне їх після
Зробіть знімок екрана в 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;
}
якщо ви хочете зафіксувати подання чи макет, наприклад RelativeLayout або LinearLayout тощо, просто використовуйте код:
LinearLayout llMain = (LinearLayout) findViewById(R.id.linearlayoutMain);
Bitmap bm = loadBitmapFromView(llMain);
тепер ви можете зберегти цю растрову карту на сховищі пристрою:
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();}