I have looked at probably every SO article concering capturing the screen (screenshot, screendump) programmatically on Android, and they usually all end up with the same answer.
The problem with it is that it captures the View that you have specified, but it does NOT capture any Dialogs that may be "on top of" the "root view". This is the code I use, that fails to capture anything "on top":
Bitmap bitmap;
View v1 = findViewById(android.R.id.content);
v1.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
File path = Environment.getExternalStorageDirectory();
File file = new File(path, "myDump.jpg");
FileOutputStream outputStream;
try
{
outputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 10, outputStream);
outputStream.flush();
outputStream.close();
}
catch (Exception e)
{
e.printStackTrace();
}
The question is: how can I capture the entire screen, including Dialogs that are on top? I am only interested in capturing the app that I am writing, not the home screen or anything like that, just anything that is on top of my root view.
I did read something about rooting, but I really hope that taking a complete screendump of the app Im writing cannot be impossible.
use this library .... it works great for me.
https://github.com/jraska/Falcon
// Saving screenshot to file
Falcon.takeScreenshot(this, imageFile);
// Take bitmap and do whatever you want
Bitmap bitmap = Falcon.takeScreenshotBitmap(this);
It is possible, you need to draw all view roots to the bitmap. Try out this library: https://github.com/jraska/Falcon it can capture Dailogs to your screenshot.
This is working inside an opened DialogFragment.
View v1 = ((ViewGroup) (((MyActivity)getActivity()).findViewById(android.R.id.content)));
v1.setDrawingCacheEnabled(true);
Bitmap bitmapParent = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
// dialogView is the inflated view of the DialogFragment
dialogView.setDrawingCacheEnabled(true);
Bitmap bitmapDialog = Bitmap.createBitmap(dialogView.getDrawingCache());
dialogView.setDrawingCacheEnabled(false);
Canvas canvas = new Canvas(bitmapParent);
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);
canvas.drawBitmap(bitmapDialog, 0, 0, paint);
// Activity and dialog captured!!
bitmapParent.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(new File(directory, name)));
Related
I need to create .jpeg/.png file on my Android application programmatically. I have simple image (black background), and it need to write some text on it programmatically. How can I do it? Is it possible?
It's definately possible.
To write text on an image you have to load the image in to a Bitmap object. Then draw on that bitmap with the Canvas and Paint functions. When you're done drawing you simply output the Bitmap to a file.
If you're just using a black background, it's probably better for you to simply create a blank bitmap on a canvas, fill it black, draw text and then dump to a Bitmap.
I used this tutorial to learn the basics of the canvas and paint.
This is the code that you'll be looking for to turn the canvas in to an image file:
OutputStream os = null;
try {
File file = new File(dir, "image" + System.currentTimeMillis() + ".png");
os = new FileOutputStream(file);
finalBMP.compress(CompressFormat.PNG, 100, os);
finalBMP.recycle(); // this is very important. make sure you always recycle your bitmap when you're done with it.
screenGrabFilePath = file.getPath();
} catch(IOException e) {
finalBMP.recycle(); // this is very important. make sure you always recycle your bitmap when you're done with it.
Log.e("combineImages", "problem combining images", e);
}
Yes, see here
Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
You can also use awt's Graphics2D with this compatibility project
Using Graphics2d you can create a PNG image as well:
public class Imagetest {
public static void main(String[] args) throws IOException {
File path = new File("image/base/path");
BufferedImage img = new BufferedImage(100, 100,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.YELLOW);
g2d.drawLine(0, 0, 50, 50);
g2d.setColor(Color.BLACK);
g2d.drawLine(50, 50, 0, 100);
g2d.setColor(Color.RED);
g2d.drawLine(50, 50, 100, 0);
g2d.setColor(Color.GREEN);
g2d.drawLine(50, 50, 100, 100);
ImageIO.write(img, "PNG", new File(path, "1.png"));
}
}
I have a LinearLayout and I am want to save the contents of that view as an image. I have it half working.
File imageFile;
// image naming and path to include sd card appending name you choose for file
String mPath = Environment.getExternalStorageDirectory().toString() + "/a.png";
// create bitmap screen capture
View v1 = getWindow().getDecorView().getRootView();
Bitmap bitmap;
v1.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
OutputStream fout = null;
imageFile = new File(mPath);
try {
fout = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.PNG, 10, fout);
fout.flush();
fout.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
With the above code it will save a copy of the view, but only what's seen on the device screen. I have more information on the view that I want saved. The code above from here and this will only save the information seen on the screen as an image. I want all the information saved, even the information that is not on the screen (where you need to scroll to see).
How can I achieve that?
Another option is to use:
Bitmap b = Bitmap.createBitmap(width, height....)
v1.setLayoutParams // Full width and height of content
Canvas c = new Canvas(b);
v1.draw(c); // You now have full bitmap
saveBitmap(b);
Run a measure/layout pass on it and draw it to a canvas. Suppose your parent was called "view" and was a vertical LinearLayout:
view.measure(someWidth, MeasureSpec.UNSPECIFIED);
Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bitmap);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.draw(c);
I am taking screenshot of Google Map v2 by using code of this
answer which is giving me output :
Which is fine to take screen shot of Map
With following code i can take the screen shot of Layout with black map screen
thats ok as with following code Map will black in ScreenShot
String mPath = Environment.getExternalStorageDirectory().toString()
+ "/" + "myTestScr" + System.currentTimeMillis() + ".jpeg";
Bitmap bitmap;
View v1 = (View) findViewById(R.id.rootviewtest);
v1.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
OutputStream fout = null;
File imageFile = new File(mPath);
try {
fout = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fout);
fout.flush();
fout.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
output of above code:
What I actually need is:
So, Now My question that how can get the output like in 3rd Screen programmatically?
Help me to take one screen shot by merging both (1 and 2) screens programmatically?
or any other alternate to merge both images programmatically after taking both ( 1 and 2 ) screen shots ?
Call the following method to take the screenshot with map:
public void captureMapScreen() {
SnapshotReadyCallback callback = new SnapshotReadyCallback() {
#Override
public void onSnapshotReady(Bitmap snapshot) {
try {
mView.setDrawingCacheEnabled(true);
Bitmap backBitmap = mView.getDrawingCache();
Bitmap bmOverlay = Bitmap.createBitmap(
backBitmap.getWidth(), backBitmap.getHeight(),
backBitmap.getConfig());
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(snapshot, new Matrix(), null);
canvas.drawBitmap(backBitmap, 0, 0, null);
FileOutputStream out = new FileOutputStream(
Environment.getExternalStorageDirectory()
+ "/MapScreenShot"
+ System.currentTimeMillis() + ".png");
bmOverlay.compress(Bitmap.CompressFormat.PNG, 90, out);
} catch (Exception e) {
e.printStackTrace();
}
}
};
mMap.snapshot(callback);
}
mview is the root view of your layout and mMap is your map fragment.
Make sure that you have the latest Google Play Services API.
mView.setDrawingCacheEnabled(true);
Bitmap backBitmap = mView.getDrawingCache();
Bitmap bmOverlay = Bitmap.createBitmap(
backBitmap.getWidth(), backBitmap.getHeight(),
backBitmap.getConfig());
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(snapshot, new Matrix(), null);
canvas.drawBitmap(backBitmap, 0, 0, null);
Skip these lines and use snapshot.compress(Bitmap.CompressFormat.PNG, 90, out); if you want the screenshot of map only.
I don't know Android API, but since you requested "alternate" methods I'll suggest using ImageMagick. On that site there are several binaries, thus I hope you can download one that suits your system. Otherwise you can download the sources (google around and you'll find many links about building it for Android).
Since I work on a Windows machine I can only tell you how you can invoke it from Windows command-line, but the syntax is similar for other platforms. This app has also a vast selection of APIs for different languages (Java, C or C++ may be of interest for you in particular), so that you can use ImageMagick embedded in your application instead of invoking it from the command line.
Now for the problem at hand: the operation you need to do is to put the "overlay sheet" with symbols over your map, like you'd do with a transparent sheet with drawings over a real map.
So let's call map.png and overlay.png the two files to be merged. Note that also the overlay file is a PNG file (more on this later). Then you can obtain something close to what you desire with the following command-line invocation:
composite.exe -compose atop overlay.png map.png output.jpg
Why must the overlay also be a PNG image? That's because we need an "overlay sheet" that is transparent in most areas (except where you have the balloon tip and the other drawings), but JPG images don't store the transparency information (they don't have the alpha-channel, which stores this information).
So you should modify the part of your code that generates the overlay so as to generate a PNG image with an appropriate alpha channel.
Hope all this helps.
I have a RelativeLayout with a loaded bitmap image using the Touch V2 example from Pragmatic Bookshelf -- http://media.pragprog.com/titles/eband3/code/Touchv2/src/org/example/touch/Touch.java
I've added a separate button with onclicklistener that when clicked will load an image from the gallery. On the activity result the image is loaded as a bitmap into the RelativeLayout:
public void getPictureFromFile(Uri targetUri){
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = scale(getContentResolver()
.openInputStream(targetUri));
workinprogress = BitmapFactory.decodeStream(
getContentResolver().openInputStream(targetUri),
null, options);
view.setImageBitmap(workinprogress);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
One the next button click, I grab the image of the relativelayout using:
thepicture.buildDrawingCache(true);
Bitmap bm = Bitmap.createBitmap(thepicture.getDrawingCache());
The process works terrific -- for the first image. When I load another image again, the bitmap passed is still the same as the original. I've tried the thepicture.invalidate() and thepicture.resetDrawableState() before getDrawingCache() but neither seem to update the image to the newly loaded picture, although the frame layout displays the correct image.
Is there something I don't understand about refreshing drawingCache that I need to implement for the second image I load?
To make it work more than once you have to use view.setDrawingCacheEnabled(true) each time before and view.setDrawingCacheEnabled(false) each time after calling view.getDrawingCache(). See the example:
imageView.setDrawingCacheEnabled(true);
imageView.buildDrawingCache(true);
File imageFile = new File(Environment.getExternalStorageDirectory(),
"Pictures/image.jpg");
FileOutputStream fileOutputStream = new FileOutputStream(imageFile);
imageView.getDrawingCache(true).compress(CompressFormat.JPEG, 100,
fileOutputStream);
fileOutputStream.close();
imageView.setDrawingCacheEnabled(false);
I am using this API demo of the Developer site, THIS DEMO.
But i am wonder that how to save that image in to My Andrtoid Device.
Is please anyone give the Code to save that drawn image to the Android Device.
Thanks.
try this code
View content = your_view;
content.setDrawingCacheEnabled(true);
content.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
Bitmap bitmap = content.getDrawingCache();
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
File file = new File(path+"/image.png");
FileOutputStream ostream;
try {
file.createNewFile();
ostream = new FileOutputStream(file);
bitmap.compress(CompressFormat.PNG, 100, ostream);
ostream.flush();
ostream.close();
Toast.makeText(getApplicationContext(), "image saved", 5000).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "error", 5000).show();
}
drawView.setDrawingCacheEnabled(true);
Bitmap bm = null;
drawView.destroyDrawingCache();
bm=drawView.getDrawingCache();
Then write the bitmap to file using bitmap factory.
One option is create another Canvas (as shown below) and repeat all your drawing on this new canvas.
Once done, call drawBitmap.
Bitmap bitmap = new Bitmap(// Set the params you like //);
Canvas canvas = new Canvas(bitmap);
// Do all your drawings here
canvas.drawBitmap(// The first picture //);
The best would be if there was a way to copy an existing canvas and then you wont need to re-draw everything but I couldn't find one.
I have implemented the below approach & worked for me.
Get your CustomView by using its id from xml file but not by instantiating the Customview.
View v = findViewById(R.id.custom_view);
//don't get customview by this way, View v = new CustomView(this);
int canvasWidth = v.getWidth();
int canvasHeight = v.getHeight();
Bitmap bitmap = Bitmap.createBitmap(canvasWidth, canvasHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
v.draw(canvas);
ImageView imageView = findViewById(R.id.image_view);
imageView.setImageBitmap(bitmap);
All code should be inside saveButton click listener.