How to correctly receive camera images from onImageAvailable? - android

I am trying to achieve video streaming from one android device to another. In order to do this I want to obtain frames from camera, send them through sockets and show on ImageView on another phone. The problem is that I have to use ImageReader with specific format - YUV_420_888. When I try to create bitmap based on bytes from this image I can only get ALPHA_8(other formats cause Exceptions saying that buffer is not big enough for pixels), which is black and white + wrongly oriented. I would like to know if there is a way to obtain correct version directly or somehow convert it so I can make a proper bitmap ready to show on ImageView. Here's some code:
public class MainActivity extends AppCompatActivity
{
private ImageReader mImageReader;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.imageView = (ImageView) findViewById(R.id.image);
this.handler = new Handler(){
#Override
public void handleMessage(Message msg)
{
if(msg.what == Worker.PROCESSED_IMAGE)
{
imageView.setImageBitmap((Bitmap) msg.obj);
}
}
};
}
private void openCamera()
{
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try
{
String cameraId = manager.getCameraIdList()[0];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[0];
mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.YUV_420_888, 50);
mImageReader.setOnImageAvailableListener(new Worker(this, this.handler, mPreviewSize.getWidth(), mPreviewSize.getHeight()), new Handler());
manager.openCamera(cameraId, mStateCallback, null);
}
catch(CameraAccessException e)
{
e.printStackTrace();
}
}
}
public class Worker implements ImageReader.OnImageAvailableListener
{
#Override
public void onImageAvailable(ImageReader imageReader)
{
Image image = imageReader.acquireLatestImage();
Image.Plane plane = image.getPlanes()[0];
ByteBuffer buffer = plane.getBuffer();
Bitmap bm = Bitmap.createBitmap(width, heigth, Bitmap.Config.ALPHA_8);
bm.copyPixelsFromBuffer(buffer);
image.close();
handler.obtainMessage(PROCESSED_IMAGE, bm).sendToTarget();
}

Almost correct, try to use this code instead:
#Override
public void onImageAvailable(ImageReader reader) {
Image image = null;
try {
image = reader.acquireLatestImage();
// Log.d(TAG, String.format(Locale.getDefault(), "image w = %d; h = %d", image.getWidth(), image.getHeight()));
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer = planes[0].getBuffer();
buffer.rewind();
byte[] data = new byte[buffer.capacity()];
buffer.get(data);
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
//use your bitmap
} catch (Exception e) {
e.printStackTrace();
}
if (image != null) {
image.close();
}
}

I used a helper function to convert image into bitmap:
Preview2.kt#image -> bitmap
Preview.kt#yuvToBitmap
protected fun yuvToBitmapFaster(bytes: ByteArray, w: Int, h: Int): Bitmap {
if (yuvType == null) {
yuvType = Type.Builder(rs, Element.U8(rs)).setX(bytes.size)
`in` = Allocation.createTyped(rs, yuvType!!.create(), Allocation.USAGE_SCRIPT)
rgbaType = Type.Builder(rs, Element.RGBA_8888(rs)).setX(w).setY(h)
out = Allocation.createTyped(rs, rgbaType?.create(), Allocation.USAGE_SCRIPT)
}
`in`?.copyFrom(bytes)
yuvToRgbIntrinsic!!.setInput(`in`)
yuvToRgbIntrinsic!!.forEach(out)
val bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
out?.copyTo(bmp)
return bmp
}
btw, Google has an example with MLkit to get camera images and process them as: VisionProcessorBase.kt and tutorial

Related

How to take picture with camera using ARCore

ARCore camera doesn't seem to support takePicture.
https://developers.google.com/ar/reference/java/com/google/ar/core/Camera
Anyone know how I can take pictures with ARCore?
I am assuming you mean a picture of what the camera is seeing and the AR objects. At a high level you need to get permission to write to external storage to save the picture, copy the frame from OpenGL and then save it as a png (for example). Here are the specifics:
Add the WRITE_EXTERNAL_STORAGE permission to the AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Then change CameraPermissionHelper to iterate over both the CAMERA and WRITE_EXTERNAL_STORAGE permissions to make sure they are granted
private static final String REQUIRED_PERMISSIONS[] = {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
};
/**
* Check to see we have the necessary permissions for this app.
*/
public static boolean hasCameraPermission(Activity activity) {
for (String p : REQUIRED_PERMISSIONS) {
if (ContextCompat.checkSelfPermission(activity, p) !=
PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* Check to see we have the necessary permissions for this app,
* and ask for them if we don't.
*/
public static void requestCameraPermission(Activity activity) {
ActivityCompat.requestPermissions(activity, REQUIRED_PERMISSIONS,
CAMERA_PERMISSION_CODE);
}
/**
* Check to see if we need to show the rationale for this permission.
*/
public static boolean shouldShowRequestPermissionRationale(Activity activity) {
for (String p : REQUIRED_PERMISSIONS) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, p)) {
return true;
}
}
return false;
}
Next, add a couple fields to HelloARActivity to keep track of the dimensions of the frame and boolean to indicate when to save the picture.
private int mWidth;
private int mHeight;
private boolean capturePicture = false;
Set the width and height in onSurfaceChanged()
public void onSurfaceChanged(GL10 gl, int width, int height) {
mDisplayRotationHelper.onSurfaceChanged(width, height);
GLES20.glViewport(0, 0, width, height);
mWidth = width;
mHeight = height;
}
At the bottom of onDrawFrame(), add a check for the capture flag. This should be done after all the other drawing happens.
if (capturePicture) {
capturePicture = false;
SavePicture();
}
Then add the onClick method for a button to take the picture, and the actual code to save the image:
public void onSavePicture(View view) {
// Here just a set a flag so we can copy
// the image from the onDrawFrame() method.
// This is required for OpenGL so we are on the rendering thread.
this.capturePicture = true;
}
/**
* Call from the GLThread to save a picture of the current frame.
*/
public void SavePicture() throws IOException {
int pixelData[] = new int[mWidth * mHeight];
// Read the pixels from the current GL frame.
IntBuffer buf = IntBuffer.wrap(pixelData);
buf.position(0);
GLES20.glReadPixels(0, 0, mWidth, mHeight,
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);
// Create a file in the Pictures/HelloAR album.
final File out = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES) + "/HelloAR", "Img" +
Long.toHexString(System.currentTimeMillis()) + ".png");
// Make sure the directory exists
if (!out.getParentFile().exists()) {
out.getParentFile().mkdirs();
}
// Convert the pixel data from RGBA to what Android wants, ARGB.
int bitmapData[] = new int[pixelData.length];
for (int i = 0; i < mHeight; i++) {
for (int j = 0; j < mWidth; j++) {
int p = pixelData[i * mWidth + j];
int b = (p & 0x00ff0000) >> 16;
int r = (p & 0x000000ff) << 16;
int ga = p & 0xff00ff00;
bitmapData[(mHeight - i - 1) * mWidth + j] = ga | r | b;
}
}
// Create a bitmap.
Bitmap bmp = Bitmap.createBitmap(bitmapData,
mWidth, mHeight, Bitmap.Config.ARGB_8888);
// Write it to disk.
FileOutputStream fos = new FileOutputStream(out);
bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
runOnUiThread(new Runnable() {
#Override
public void run() {
showSnackbarMessage("Wrote " + out.getName(), false);
}
});
}
Last step is to add the button to the end of activity_main.xml layout
<Button
android:id="#+id/fboRecord_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#+id/surfaceview"
android:layout_alignTop="#+id/surfaceview"
android:onClick="onSavePicture"
android:text="Snap"
tools:ignore="OnClick"/>
Acquiring the image buffer
In the latest ARCore SDK, we get access to the image buffer via public class Frame. Below is the sample code which gives us access to the image buffer.
private void onSceneUpdate(FrameTime frameTime) {
try {
Frame currentFrame = sceneView.getArFrame();
Image currentImage = currentFrame.acquireCameraImage();
int imageFormat = currentImage.getFormat();
if (imageFormat == ImageFormat.YUV_420_888) {
Log.d("ImageFormat", "Image format is YUV_420_888");
}
}
onSceneUpdate() will be called for every update if you register it to setOnUpdateListener() callback. Image will be in YUV_420_888 format, but it will have full Field of view of native high resolution camera.
Also do not forget to close resources of received image by calling currentImage.close(). Otherwise you will receive a ResourceExhaustedException on the next run of onSceneUpdate.
Writing the acquired image buffer to a file
Following implementation converts YUV buffer to compressed JPEG byte array
private static byte[] NV21toJPEG(byte[] nv21, int width, int height) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
YuvImage yuv = new YuvImage(nv21, ImageFormat.NV21, width, height, null);
yuv.compressToJpeg(new Rect(0, 0, width, height), 100, out);
return out.toByteArray();
}
public static void WriteImageInformation(Image image, String path) {
byte[] data = null;
data = NV21toJPEG(YUV_420_888toNV21(image),
image.getWidth(), image.getHeight());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(path));
bos.write(data);
bos.flush();
bos.close();
}
private static byte[] YUV_420_888toNV21(Image image) {
byte[] nv21;
ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();
int ySize = yBuffer.remaining();
int uSize = uBuffer.remaining();
int vSize = vBuffer.remaining();
nv21 = new byte[ySize + uSize + vSize];
//U and V are swapped
yBuffer.get(nv21, 0, ySize);
vBuffer.get(nv21, ySize, vSize);
uBuffer.get(nv21, ySize + vSize, uSize);
return nv21;
}
Sorry for answering late.You can use code to click picture in ARCore:
private String generateFilename() {
String date =
new SimpleDateFormat("yyyyMMddHHmmss", java.util.Locale.getDefault()).format(new Date());
return Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES) + File.separator + "Sceneform/" + date + "_screenshot.jpg";
}
private void saveBitmapToDisk(Bitmap bitmap, String filename) throws IOException {
File out = new File(filename);
if (!out.getParentFile().exists()) {
out.getParentFile().mkdirs();
}
try (FileOutputStream outputStream = new FileOutputStream(filename);
ByteArrayOutputStream outputData = new ByteArrayOutputStream()) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputData);
outputData.writeTo(outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException ex) {
throw new IOException("Failed to save bitmap to disk", ex);
}
}
private void takePhoto() {
final String filename = generateFilename();
/*ArSceneView view = fragment.getArSceneView();*/
mSurfaceView = findViewById(R.id.surfaceview);
// Create a bitmap the size of the scene view.
final Bitmap bitmap = Bitmap.createBitmap(mSurfaceView.getWidth(), mSurfaceView.getHeight(),
Bitmap.Config.ARGB_8888);
// Create a handler thread to offload the processing of the image.
final HandlerThread handlerThread = new HandlerThread("PixelCopier");
handlerThread.start();
// Make the request to copy.
PixelCopy.request(mSurfaceView, bitmap, (copyResult) -> {
if (copyResult == PixelCopy.SUCCESS) {
try {
saveBitmapToDisk(bitmap, filename);
} catch (IOException e) {
Toast toast = Toast.makeText(DrawAR.this, e.toString(),
Toast.LENGTH_LONG);
toast.show();
return;
}
Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content),
"Photo saved", Snackbar.LENGTH_LONG);
snackbar.setAction("Open in Photos", v -> {
File photoFile = new File(filename);
Uri photoURI = FileProvider.getUriForFile(DrawAR.this,
DrawAR.this.getPackageName() + ".ar.codelab.name.provider",
photoFile);
Intent intent = new Intent(Intent.ACTION_VIEW, photoURI);
intent.setDataAndType(photoURI, "image/*");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
});
snackbar.show();
} else {
Log.d("DrawAR", "Failed to copyPixels: " + copyResult);
Toast toast = Toast.makeText(DrawAR.this,
"Failed to copyPixels: " + copyResult, Toast.LENGTH_LONG);
toast.show();
}
handlerThread.quitSafely();
}, new Handler(handlerThread.getLooper()));
}

I use android.hardware.camera2, CDS enable 0 num_str 1 applied 0 stream_id 5

I'm using camera2 to record video,There was an error.
ImageReader
mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),ImageFormat.YUV_420_888, 5);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, null);
OnImageAvailableListener
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
= new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader reader) {
Log.d("---------->", "mOnPreviewAvailableListener" + reader);
try (Image image = reader.acquireNextImage()) {
Image.Plane[] planes = image.getPlanes();
}
}
};
PreviewRequestBuilder
mPreviewRequestBuilder.addTarget(mImageReader.getSurface());

How to get single preview frame in Camera2 API Android 5.0?

I'm trying to get a preview frame for QR code scanning functionality using Camera2 API. In old Camera API it's as easy as:
android.hardware.Camera mCamera;
...
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
// will be invoked for every preview frame in addition to displaying them on the screen
}
});
However, I can't find a way to achieve that using new Camera2 API. I'd like to receive multiple frames that I can work on - the best would be to receive byte array as in old API. Any ideas how to do that?
A little late but better than never:
Usually a TextureView is used to display the preview of the camera. You can use TextureView.SurfaceTextureListener to get a callback every time the surface changes. TextureView does provide a method getBitmap(Bitmap) which you can use to get the preview frame in the same size as the TextureView.
You can use this Google sample as starting point. Simply update the surfaceTextureListener like shown here:
private val surfaceTextureListener = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureAvailable(texture: SurfaceTexture, width: Int, height: Int) {
openCamera(width, height)
}
override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) {
configureTransform(width, height)
}
override fun onSurfaceTextureDestroyed(texture: SurfaceTexture) = true
override fun onSurfaceTextureUpdated(texture: SurfaceTexture) {
// Start changes
// Get the bitmap
val frame = Bitmap.createBitmap(textureView.width, textureView.height, Bitmap.Config.ARGB_8888)
textureView.getBitmap(frame)
// Do whatever you like with the frame
frameProcessor?.processFrame(frame)
// End changes
}
}
Use Below code to do so.
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSizes = null;
if (characteristics != null) {
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
}
int width = 480;//480x320
int height = 320;
if (jpegSizes != null && 0 < jpegSizes.length) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurfaces = new ArrayList<Surface>(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
// Orientation
int rotation = ((Activity) context).getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
final File file = getFileDir();
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader reader) {
Image image = null;
try {
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
save(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (image != null) {
image.close();
}
}
}
private void save(byte[] bytes) throws IOException {
OutputStream output = null;
try {
output = new FileOutputStream(file);
output.write(bytes);
} finally {
if (null != output) {
output.close();
}
}
}
};
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}

how to create and save a screenshot from a surfaceview?

I have an app that I want to be able to capture a screenshot
Here is my code :
public class Screenshot {
private final View view;
/** Create snapshots based on the view and its children. */
public Screenshot(View root) {
this.view = root;
}
/** Create snapshot handler that captures the root of the whole activity. */
public Screenshot(Activity activity) {
final View contentView = activity.findViewById(android.R.id.content);
this.view = contentView.getRootView();
}
/** Take a snapshot of the view. */
public Bitmap snap() {
Bitmap bitmap = Bitmap.createBitmap(this.view.getWidth(), this.view.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
}
but the contents of the surfaceView is saved as black.!!!
Please help me, Thanks...
I hope you have used this solution which was posted here Get screenshot of surfaceView in Android
this thing is explained here Take Screenshot of SurfaceView
The SurfaceView's surface is independent of the surface on which View elements are drawn. So capturing the View contents won't include the SurfaceView.........
I hope this Taking screenshot programmatically doesnt capture the contents of surfaceVIew code can help you out more
public class Cam_View extends Activity implements SurfaceHolder.Callback {
protected static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 0;
private SurfaceView SurView;
private SurfaceHolder camHolder;
private boolean previewRunning;
final Context context = this;
public static Camera camera = null;
private RelativeLayout CamView;
private Bitmap inputBMP = null, bmp, bmp1;
private ImageView mImage;
#SuppressWarnings("deprecation")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera);
CamView = (RelativeLayout) findViewById(R.id.camview);//RELATIVELAYOUT OR
//ANY LAYOUT OF YOUR XML
SurView = (SurfaceView)findViewById(R.id.sview);//SURFACEVIEW FOR THE PREVIEW
//OF THE CAMERA FEED
camHolder = SurView.getHolder(); //NEEDED FOR THE PREVIEW
camHolder.addCallback(this); //NEEDED FOR THE PREVIEW
camHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//NEEDED FOR THE PREVIEW
camera_image = (ImageView) findViewById(R.id.camera_image);//NEEDED FOR THE PREVIEW
Button btn = (Button) findViewById(R.id.button1); //THE BUTTON FOR TAKING PICTURE
btn.setOnClickListener(new OnClickListener() { //THE BUTTON CODE
public void onClick(View v) {
camera.takePicture(null, null, mPicture);//TAKING THE PICTURE
//THE mPicture IS CALLED
//WHICH IS THE LAST METHOD(SEE BELOW)
}
});
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,//NEEDED FOR THE PREVIEW
int height) {
if(previewRunning) {
camera.stopPreview();
}
Camera.Parameters camParams = camera.getParameters();
Camera.Size size = camParams.getSupportedPreviewSizes().get(0);
camParams.setPreviewSize(size.width, size.height);
camera.setParameters(camParams);
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
previewRunning=true;
} catch(IOException e) {
e.printStackTrace();
}
}
public void surfaceCreated(SurfaceHolder holder) { //NEEDED FOR THE PREVIEW
try {
camera=Camera.open();
} catch(Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show();
finish();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) { //NEEDED FOR THE PREVIEW
camera.stopPreview();
camera.release();
camera=null;
}
public void TakeScreenshot(){ //THIS METHOD TAKES A SCREENSHOT AND SAVES IT AS .jpg
Random num = new Random();
int nu=num.nextInt(1000); //PRODUCING A RANDOM NUMBER FOR FILE NAME
CamView.setDrawingCacheEnabled(true); //CamView OR THE NAME OF YOUR LAYOUR
CamView.buildDrawingCache(true);
Bitmap bmp = Bitmap.createBitmap(CamView.getDrawingCache());
CamView.setDrawingCacheEnabled(false); // clear drawing cache
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bmp.compress(CompressFormat.JPEG, 100, bos);
byte[] bitmapdata = bos.toByteArray();
ByteArrayInputStream fis = new ByteArrayInputStream(bitmapdata);
String picId=String.valueOf(nu);
String myfile="Ghost"+picId+".jpeg";
File dir_image = new File(Environment.getExternalStorageDirectory()+//<---
File.separator+"Ultimate Entity Detector"); //<---
dir_image.mkdirs(); //<---
//^IN THESE 3 LINES YOU SET THE FOLDER PATH/NAME . HERE I CHOOSE TO SAVE
//THE FILE IN THE SD CARD IN THE FOLDER "Ultimate Entity Detector"
try {
File tmpFile = new File(dir_image,myfile);
FileOutputStream fos = new FileOutputStream(tmpFile);
byte[] buf = new byte[1024];
int len;
while ((len = fis.read(buf)) > 0) {
fos.write(buf, 0, len);
}
fis.close();
fos.close();
Toast.makeText(getApplicationContext(),
"The file is saved at :SD/Ultimate Entity Detector",Toast.LENGTH_LONG).show();
bmp1 = null;
camera_image.setImageBitmap(bmp1); //RESETING THE PREVIEW
camera.startPreview(); //RESETING THE PREVIEW
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private PictureCallback mPicture = new PictureCallback() { //THIS METHOD AND THE METHOD BELOW
//CONVERT THE CAPTURED IMAGE IN A JPG FILE AND SAVE IT
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File dir_image2 = new File(Environment.getExternalStorageDirectory()+
File.separator+"Ultimate Entity Detector");
dir_image2.mkdirs(); //AGAIN CHOOSING FOLDER FOR THE PICTURE(WHICH IS LIKE A SURFACEVIEW
//SCREENSHOT)
File tmpFile = new File(dir_image2,"TempGhost.jpg"); //MAKING A FILE IN THE PATH
//dir_image2(SEE RIGHT ABOVE) AND NAMING IT "TempGhost.jpg" OR ANYTHING ELSE
try { //SAVING
FileOutputStream fos = new FileOutputStream(tmpFile);
fos.write(data);
fos.close();
//grabImage();
} catch (FileNotFoundException e) {
Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show();
} catch (IOException e) {
Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show();
}
String path = (Environment.getExternalStorageDirectory()+
File.separator+"Ultimate EntityDetector"+
File.separator+"TempGhost.jpg");//<---
BitmapFactory.Options options = new BitmapFactory.Options();//<---
options.inPreferredConfig = Bitmap.Config.ARGB_8888;//<---
bmp1 = BitmapFactory.decodeFile(path, options);//<--- *********(SEE BELOW)
//THE LINES ABOVE READ THE FILE WE SAVED BEFORE AND CONVERT IT INTO A BitMap
camera_image.setImageBitmap(bmp1); //SETTING THE BitMap AS IMAGE IN AN IMAGEVIEW(SOMETHING
//LIKE A BACKGROUNG FOR THE LAYOUT)
tmpFile.delete();
TakeScreenshot();//CALLING THIS METHOD TO TAKE A SCREENSHOT
//********* THAT LINE MIGHT CAUSE A CRASH ON SOME PHONES (LIKE XPERIA T)<----(SEE HERE)
//IF THAT HAPPENDS USE THE LINE "bmp1 =decodeFile(tmpFile);" WITH THE METHOD BELOW
}
};
public Bitmap decodeFile(File f) { //FUNCTION BY Arshad Parwez
Bitmap b = null;
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream fis = new FileInputStream(f);
BitmapFactory.decodeStream(fis, null, o);
fis.close();
int IMAGE_MAX_SIZE = 1000;
int scale = 1;
if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
scale = (int) Math.pow(
2,
(int) Math.round(Math.log(IMAGE_MAX_SIZE
/ (double) Math.max(o.outHeight, o.outWidth))
/ Math.log(0.5)));
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
fis = new FileInputStream(f);
b = BitmapFactory.decodeStream(fis, null, o2);
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
return b;
}
}
try out this also
public static Bitmap overlay(Bitmap bmp1,Bitmap bmp2) {
Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth(), bmp1.getHeight(), bmp1.getConfig());
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(bmp1, 0,0, null);
canvas.drawBitmap(bmp2, 0, 0, null);
Log.i("bmOverlay.......",""+bmOverlay);
bmp3=bmOverlay;
return bmOverlay;
}
private void getScreen() {
Toast.makeText(BookType1.this, "saved", Toast.LENGTH_SHORT).show();
File myDir=new File("/sdcard/saved_images");
myDir.mkdirs();
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "Image-"+ n +".png";
File file = new File (myDir, fname);
try
{
FileOutputStream ostream = new FileOutputStream(file);
bmp3.compress(CompressFormat.PNG, 100, ostream);
ostream.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
and you can also go through these references which gives you more idea
How to capture screenshot of surfaceview with background
Taking screen shot of a SurfaceView in android
How to take a screenshot of Android's Surface View?
How to programmatically take a screenshot in Android?

saving Zbar barcode as image

I want to use barcode scanner into my application and i am using Zbar library
however, i can scan barcode but i want to save scanned image into sd card.
So far, i can able to capture image and save into SD but when i try to open it i have broken image error and cannot display it.
What am i using is :
private final Camera.PreviewCallback saveImage = new Camera.PreviewCallback()
{
#Override
public void onPreviewFrame(byte[] data, Camera camera)
{
mCamera.setPreviewCallback(null);
String path = Environment.getExternalStorageDirectory() + "/DCIM/mcs_" + timeStamp + ".jpg";
FileOutputStream fos = null;
try
{
fos = new FileOutputStream(path);
fos.write(data);
fos.close();
}
catch(Exception e)
{
}
}
};
PreviewCallback previewCb = new PreviewCallback()
{
public void onPreviewFrame(byte[] data, Camera camera)
{
Camera.Parameters parameters = camera.getParameters();
Size size = parameters.getPreviewSize();
Image barcode = new Image(size.width, size.height);
barcode.setData(data);
barcode = barcode.convert("Y800");
int result = scanner.scanImage(barcode);
if (result != 0)
{
mCamera.setPreviewCallback(saveImage);
mCamera.stopPreview();
SymbolSet syms = scanner.getResults();
for (Symbol sym : syms)
{
Intent intent = new Intent(getApplicationContext(), ScanCodeResult.class);
intent.putExtra("timeStamp", timeStamp);
intent.putExtra("result", sym.getData().toString());
//startActivity(intent);
break;
}
}
}
};
#Override
public void onPreviewFrame(byte[] data, Camera camera)
{
Size size = camera.getParameters().getPreviewSize(); //获取预览大小
final int w = size.width; //宽度
final int h = size.height;
final YuvImage image = new YuvImage(data, ImageFormat.NV21, w, h, null);
ByteArrayOutputStream os = new ByteArrayOutputStream(data.length);
if(!image.compressToJpeg(new Rect(0, 0, w, h), 100, os)){
return;
}
byte[] tmp = os.toByteArray();
Bitmap bmp = BitmapFactory.decodeByteArray(tmp, 0,tmp.length);
FileHelper fileHelper = new FileHelper();
fileHelper.storeInSD(bmp);
}

Categories

Resources