I want to programmatically take screen shot of my android application which is a video calling application by using openSIPS protocol. While on the video call, I need to take the screen shots. I have already tried something but it gives the screenshot except the videocall fragment.
Here is my try:
public static Bitmap takeScreenshot() {
View rootView = mVideoView.getRootView();
rootView.setDrawingCacheEnabled(true);
//rootView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY),
//MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY));
// rootView.layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
rootView.buildDrawingCache(true);
// rootView.destroyDrawingCache();
return rootView.getDrawingCache();
}
The videoView extends an SurfaceView, which has its content not go through the drawing cache, thus getting it will only returnes a black screen instead of a capture of the video layout. Any help will be appreciated.
Ok now, I got the perfect answer for me.
Here it is.
if (InCallActivity.capture) {
int widthx = width;
int heightx = height;
int screenshotSize = widthx * heightx;
ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 4);
bb.order(ByteOrder.nativeOrder());
gl.glReadPixels(0, 0, widthx, heightx, GL10.GL_RGBA,
GL10.GL_UNSIGNED_BYTE, bb);
int pixelsBuffer[] = new int[screenshotSize];
bb.asIntBuffer().get(pixelsBuffer);
bb = null;
Bitmap bitmap = Bitmap.createBitmap(widthx, heightx,
Bitmap.Config.RGB_565);
bitmap.setPixels(pixelsBuffer, screenshotSize - widthx,
-widthx, 0, 0, widthx, heightx);
pixelsBuffer = null;
short sBuffer[] = new short[screenshotSize];
ShortBuffer sb = ShortBuffer.wrap(sBuffer);
bitmap.copyPixelsToBuffer(sb);
// Making created bitmap (from OpenGL points) compatible with
// Android bitmap
for (int i = 0; i < screenshotSize; ++i) {
short v = sBuffer[i];
sBuffer[i] = (short) (((v & 0x1f) << 11) | (v & 0x7e0) | ((v & 0xf800) >> 11));
}
sb.rewind();
bitmap.copyPixelsFromBuffer(sb);
InCallActivity.captureBmp = bitmap.copy(
Bitmap.Config.ARGB_8888, false);
InCallActivity.capture = false;
}
I put this code inside onDrawFrame(GL10 gl) method of my class Renderer , and it seems working. Here InCallActivity is the class where I using the GlSurfaceView.
I got this answer from this link. Thanks for supports. Happy coding :)
You can try something like that
Bitmap bitmap;
View v1 = findViewById(R.id.rlid);// get ur root view id
v1.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
and then for saving
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 40, bytes);
File f = new File(Environment.getExternalStorageDirectory()
+ File.separator + "test.jpg")
f.createNewFile();
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
fo.close();
Source: how to take screenshot programmatically and save it on gallery?
or you can also check this link How to programmatically take a screenshot in Android?
Related
Is there a way to get an image of the current live wallpaper using the WallpaperManager API? I tried the following code, but it simply returned the the icon of the app that was used to set the wallpaper.
PackageManager pm = getApplicationContext().getPackageManager();
// Check if user has set a live wallpaper
if (WallpaperManager.getInstance(this).getWallpaperInfo() != null) {
Drawable wallpaperDrawable = WallpaperManager.getInstance(this).getWallpaperInfo().loadThumbnail(pm);
}
Have you tried to use MediaProjection API to achieve this. I suggest to look along the following code. For more information about the API refer this.
//You have to start the Screen Capture based on an action.
//mWidth, mHeight depends on device screen width, height
mImageReader = ImageReader.newInstance(mWidth, mHeight, PixelFormat.RGBA_8888, 2);
mVirtualDisplay = sMediaProjection.createVirtualDisplay(SCREENCAP_NAME, mWidth, mHeight, mDensity, VIRTUAL_DISPLAY_FLAGS, mImageReader.getSurface(), null, mHandler);
mImageReader.setOnImageAvailableListener(new ImageAvailableListener(), mHandler)
startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);
//Then convert the media captured to an Image
sMediaProjection.stop();
image = mImageReader.acquireLatestImage();
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer = planes[0].getBuffer();
bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "SNAPSHOT.jpg");
fos = new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG, 100, fos);
fos.close();
I got a problem with an Air Native Extension in Android.
The ANE receive a Bitmap from the Actionscript side, compress it in jpeg format and send it back to the Actionscript that will write it on the storage.
Everything is good but one last thing.
It seems that the channels order for Actionscript is different than in Android, so my compressed image have RED colors in place of BLUE.. here is the code:
Actionscript (I'm using a library called deng.fzip.FZipLibrary to get the bitmap from a zip package)
__image = __fl.getBitmapData(path);
__de = new DataExchange();
__ba = __de.bitmapEncode(__image) as ByteArray;
Android
...
try {
inputValue = (FREBitmapData)arg1[0];
inputValue.acquire();
int srcWidth = inputValue.getWidth();
int srcHeight = inputValue.getHeight();
Bitmap bm = Bitmap.createBitmap(srcWidth, srcHeight, Config.ARGB_8888);
bm.copyPixelsFromBuffer(inputValue.getBits());
ByteArrayOutputStream os = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 80, os);
compressed = os.toByteArray();
inputValue.release();
} catch (Exception e) {
e.printStackTrace();
}
try {
returnValue = FREByteArray.newByteArray();
returnValue.setProperty("length", FREObject.newObject(compressed.length));
returnValue.acquire();
ByteBuffer returnBytes = returnValue.getBytes();
returnBytes.put(compressed, 0, compressed.length);
returnValue.release();
}
...
Anyone have an idea on how to convert the red to blue in the android side before send the image back? Or it needs to be done in the actionscript side?
Thank you very much and regards,
Gianpiero
You can switch the colors like this:
(This code does not origin from me, unfortunately I forgot where I found it, so credit goes somewhere else)
private Bitmap m_encodingBitmap = null;
private Canvas m_canvas = null;
private Paint m_paint = null;
private final float[] m_bgrToRgbColorTransform =
{
0, 0, 1f, 0, 0,
0, 1f, 0, 0, 0,
1f, 0, 0, 0, 0,
0, 0, 0, 1f, 0
};
private final ColorMatrix m_colorMatrix = new ColorMatrix(m_bgrToRgbColorTransform);
private final ColorMatrixColorFilter m_colorFilter = new ColorMatrixColorFilter(m_colorMatrix);
...
try{
FREBitmapData as3Bitmap = (FREBitmapData)args[0];
as3Bitmap.acquire();
m_encodingBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
m_canvas = new Canvas(m_encodingBitmap);
m_paint = new Paint();
m_paint.setColorFilter(m_colorFilter);
m_encodingBitmap.copyPixelsFromBuffer(as3BitmapBytes);
as3Bitmap.release();
//
// Convert the bitmap from BGRA to RGBA.
//
m_canvas.drawBitmap(m_encodingBitmap, 0, 0, m_paint);
...
}
Hope that helps ... Timm
Is it possible to get a full bitmap from a viewgroup-object?
This code takes a 'screenshot' off the view group that's currently on the screen, but I want the whole view, also what's not currently on the screen.
public void export(ViewGroup view){
view.setDrawingCacheEnabled(true);
view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
Bitmap bitmap = view.getDrawingCache(true);
}
Here I used ScrollView to get the whole view to bitmap
so Here u can use instead of scrollview anyother view group like linerlayout etc..
Bitmap map = loadBitmapFromView(getApplicationContext(),scrollView);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
map.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
//you can create a new file name "test.jpg" in sdcard folder.
File f = new File("/sdcard" +"/" + "mainemailpdf.jpg");
f.createNewFile();
//write the bytes in file
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
bArray = bytes.toByteArray();
// remember close de FileOutput
fo.close();
and for loadBitmapFromView method is:
public static Bitmap loadBitmapFromView(Context context, View v) {
Toast.makeText(context,
v.getMeasuredHeight() + "::::::::::::" + v.getMeasuredWidth(),
Toast.LENGTH_LONG).show();
if (v.getMeasuredHeight() > 0) {
v.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getWidth(), v.getWidth());
v.draw(c);
return b;
}
return null;
}
I hope it helps :)
Any query let me know.
It is not possible since Android system scales down the bitmap.
For ex - if your bitmap size is 480*800 then its size is 480*800*4 = 1536000.
The multiplication with 4 is because each pixel is 4 bytes - RGBA.
Meaning more than a mega and a half for every unscaled image. If the Android won't scale down image you will probably get
OutOfMemoryException after a few image loadings.
as
you have 3 options:
1) view.draw(canvas) you'll get the visible portion of the image(only what is actually being drawn to the screen)
2) getDrawingCache() - will give you the scaled down image.
3) Create custom view which saves the bitmap to the disk and loads it from there when requested
I tried :
process = Runtime.getRuntime().exec("su -c cat /dev/graphics/fb0 > /sdcard/frame.raw");
process.waitFor();
but it doesn't work. My device is rooted.
I see many answers that it requires rooted access, but no actual code to get the framebuffer.
I also tried glReadPixels() but no luck.
public void TakeScreen() {
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
int screenshotSize = width * height;
ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 4);
bb.order(ByteOrder.nativeOrder());
gl.glReadPixels(0, 0, width, height, GL10.GL_RGBA,
GL10.GL_UNSIGNED_BYTE, bb);
int pixelsBuffer[] = new int[screenshotSize];
bb.asIntBuffer().get(pixelsBuffer);
bb = null;
Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.RGB_565);
bitmap.setPixels(pixelsBuffer, screenshotSize - width, -width, 0, 0,
width, height);
pixelsBuffer = null;
short sBuffer[] = new short[screenshotSize];
ShortBuffer sb = ShortBuffer.wrap(sBuffer);
bitmap.copyPixelsToBuffer(sb);
for (int i = 0; i < screenshotSize; ++i) {
short v = sBuffer[i];
sBuffer[i] = (short) (((v & 0x1f) << 11) | (v & 0x7e0) | ((v & 0xf800) >> 11));
}
sb.rewind();
bitmap.copyPixelsFromBuffer(sb);
saveBitmap(bitmap, "/screenshots", "capturedImage");
}
Seems to me like your problem is this sign: >. You cannot redirect output using exec. What you need to do is grab the output stream of the process (which is the input stream for you) and store it to file;
process = Runtime.getRuntime().exec("su -c cat /dev/graphics/fb0");
InputStream is = process.getInputStream();
...
The answer lies in replicating the way the device itself handles it:
fb = open("/dev/graphics/fb0", O_RDONLY);
check this
I'm trying to take a screenshot of Android OpenGL.
The code I found is as follows:
nt size = width * height;
ByteBuffer buf = ByteBuffer.allocateDirect(size * 4);
buf.order(ByteOrder.nativeOrder());
glContext.glReadPixels(0, 0, width, height, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, buf);
int data[] = new int[size];
buf.asIntBuffer().get(data);
buf = null;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
bitmap.setPixels(data, size-width, -width, 0, 0, width, height);
data = null;
short sdata[] = new short[size];
ShortBuffer sbuf = ShortBuffer.wrap(sdata);
bitmap.copyPixelsToBuffer(sbuf);
for (int i = 0; i < size; ++i) {
//BGR-565 to RGB-565
short v = sdata[i];
sdata[i] = (short) (((v&0x1f) << 11) | (v&0x7e0) | ((v&0xf800) >> 11));
}
sbuf.rewind();
bitmap.copyPixelsFromBuffer(sbuf);
try {
FileOutputStream fos = new FileOutputStream("/sdcard/screeshot.png");
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
} catch (Exception e) {
// handle
}
I tried also a code from that site
link text
In each case the result is a png file which is completely black.
I found there is some problem with glReadPixels method but I don't know how to bypass it.
Sorry for the late response...
In order to perform a correct screenshot You have to put into Your onDrawFrame(GL10 gl) handler the following code:
if(screenshot){
int screenshotSize = width * height;
ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 4);
bb.order(ByteOrder.nativeOrder());
gl.glReadPixels(0, 0, width, height, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, bb);
int pixelsBuffer[] = new int[screenshotSize];
bb.asIntBuffer().get(pixelsBuffer);
bb = null;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
bitmap.setPixels(pixelsBuffer, screenshotSize-width, -width, 0, 0, width, height);
pixelsBuffer = null;
short sBuffer[] = new short[screenshotSize];
ShortBuffer sb = ShortBuffer.wrap(sBuffer);
bitmap.copyPixelsToBuffer(sb);
//Making created bitmap (from OpenGL points) compatible with Android bitmap
for (int i = 0; i < screenshotSize; ++i) {
short v = sBuffer[i];
sBuffer[i] = (short) (((v&0x1f) << 11) | (v&0x7e0) | ((v&0xf800) >> 11));
}
sb.rewind();
bitmap.copyPixelsFromBuffer(sb);
lastScreenshot = bitmap;
screenshot = false;
}
The "screenshot" class field is set to true whenever the user presses the button to create a screenshot
or at any other circumstances You want. Inside the "if" body You may place any screenshot creating code sample You find in th internet - the most important thing is having the current instance of GL10. For example when You just save the GL10 instance to the class variable and then use it outside the event to create the screenshot You'll end up with the completely blank image. That's why You have to take a screenshot inside the OnDrawFrame event handler where the GL10 instance is the current one.
Hope that it helps.
Best regards, Gordon.
Here is the way to do it if you want to preserve the quality (8 bits for every colour channel: red, green, blue and alpha too):
if (this.screenshot) {
int screenshotSize = this.width * this.height;
ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 4);
bb.order(ByteOrder.nativeOrder());
gl.glReadPixels(0, 0, width, height, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, bb);
int pixelsBuffer[] = new int[screenshotSize];
bb.asIntBuffer().get(pixelsBuffer);
bb = null;
for (int i = 0; i < screenshotSize; ++i) {
// The alpha and green channels' positions are preserved while the red and blue are swapped
pixelsBuffer[i] = ((pixelsBuffer[i] & 0xff00ff00)) | ((pixelsBuffer[i] & 0x000000ff) << 16) | ((pixelsBuffer[i] & 0x00ff0000) >> 16);
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixelsBuffer, screenshotSize-width, -width, 0, 0, width, height);
this.screenshot = false;
}
Got it!
My mistake was that I was remembering GL context in the class variable. In order to take a screenshot I have to use the gl context passed to the OnDraw in the class implementing GLSurfaceView.Renderer interface. I simply use my code in the "if" clause and everything works as expected. Hope that remark would help anyone.
Best regards,
Gordon