I can capturing, cropping, resizing and saving photos. Saving photos with same resolution (133x171). I need this resolution and greather than 20KB jpeg file size.
Sometimes it capture smaller than 20KB. I want to save all photos greather than 20KB.
JPEG Quality: 100
StartPreview Codes
public void surfaceCreated(SurfaceHolder holder) {
setWillNotDraw(false);
Log.d("Variable", "surfaceCreated");
try {
mCamera.setPreviewDisplay(holder);
Camera.Parameters parameters = mCamera.getParameters();
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
}
parameters.set("jpeg-quality", 100);
mCamera.setParameters(parameters);
mCamera.startPreview();
} catch (IOException e) {
Log.d("Method.surfaceCreated", "Error setting camera preview: " + e.getMessage());
}
}
PictureTaken method:
#Override
public void onPictureTaken(byte[] data, Camera camera) {
// TODO Auto-generated method stub
/*Bitmap bitmapPicture = BitmapFactory.decodeByteArray(arg0, 0, arg0.length); */
File pictureFile = getOutputMediaFile();
if (pictureFile == null){
Log.d("Method.PictureCall", "Error creating media file, check storage permissions: ");
return;
}
data = cropImage(data);
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
Toast.makeText(c, "saved: " + pictureFile.toString(), Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
Log.d("Method.PictureCallBack", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("Method.PictureCallBack", "Error accessing file: " + e.getMessage());
}
camera.startPreview();
}
cropImage Method:
public byte[] cropImage (byte[] data) {
Point start_xy = getCaptureStartPoint();
Point cropRes = getCaptureResolution();
int stride = cropRes.x;
int[] pixels = new int[cropRes.x * cropRes.y];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Bitmap bitmap = BitmapFactory.decodeByteArray(data , 0, data.length);
bitmap = rotateBitmap(bitmap, 90);
bitmap.getPixels(pixels, 0, stride, start_xy.x, start_xy.y, cropRes.x, cropRes.y);
bitmap = Bitmap.createBitmap(pixels, 0, stride, cropRes.x, cropRes.y, Config.ARGB_8888);
bitmap = Bitmap.createScaledBitmap(bitmap, efoto_x, efoto_y, false);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
return bos.toByteArray();
}
UPDATE #1:
Perhaps this isn't best way. But I tried. After write picture file to storage adding some EXIF data to image with this method.
private void addEXIFData(final File f) throws IOException {
ExifInterface exif = new ExifInterface(f.getAbsolutePath());
exif.setAttribute(ExifInterface.TAG_MAKE, "Photo Photo Photo Photo........ bla bla blaaaaa");
exif.setAttribute(ExifInterface.TAG_MODEL, "Photo Photo Photo Photo........ bla bla blaaaaa");
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "90");
exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH, "150");
exif.saveAttributes();
}
Related
I am taking an image from camera using:
mCamera.takePicture(null, null,
new PhotoHandler(getApplicationContext()));
But the image I am taking is landscape and I want it portrait, I tried converting the file into bitmap, rotate it and then save it again, here is my onPictureTaken() function and rotate() function inside PhotoHandler.class:
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFileDir = getDir();
if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {
Log.d("Error", "Can't create directory to save image.");
Toast.makeText(context, "Can't create directory to save image.",
Toast.LENGTH_LONG).show();
return;
}
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
String date = dateFormat.format(new Date());
String photoFile = "Picture_" + date + ".jpg";
String filename = pictureFileDir.getPath() + File.separator + photoFile;
pictureFile = new File(filename);
st1 = pictureFile.getAbsolutePath();
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
Toast.makeText(context, "New Image saved:" + photoFile,
Toast.LENGTH_LONG).show();
} catch (Exception error) {
Log.d("Error", "File" + filename + "not saved: "
+ error.getMessage());
Toast.makeText(context, "Image could not be saved.",
Toast.LENGTH_LONG).show();
}
Bitmap b = rotate(BitmapFactory.decodeFile(pictureFile.getAbsolutePath()),270);
FileOutputStream out = null;
try {
out = new FileOutputStream(pictureFile);
b.compress(Bitmap.CompressFormat.PNG, 100, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
CameraPreview.safeToTakePicture = true;
galleryAddPic();
}
public static Bitmap rotate(Bitmap bitmap, int degree) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
mtx.setRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
Anyway, it takes too long, I tried using mCamera.setDisplayOrientation(90); but it changes only the preview of the camera, the picture taken is still the same, I also tried getting the parameters of the camera and changing it like here:
Camera.Parameters parameters = mCamera.getParameters();
parameters.set("orientation", "portrait");
mCamera.setParameters(parameters);
Without success, any help will be appreciated.
EDIT :
New code:
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFileDir = getDir();
if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {
Log.d("Error", "Can't create directory to save image.");
Toast.makeText(context, "Can't create directory to save image.",
Toast.LENGTH_LONG).show();
return;
}
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
String date = dateFormat.format(new Date());
String photoFile = "Picture_" + date + ".jpg";
String filename = pictureFileDir.getPath() + File.separator + photoFile;
pictureFile = new File(filename);
st1 = pictureFile.getAbsolutePath();
Bitmap b = rotate(BitmapFactory.decodeByteArray(data,0,data.length),270);
FileOutputStream out = null;
try {
out = new FileOutputStream(pictureFile);
b.compress(Bitmap.CompressFormat.PNG, 100, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
CameraPreview.safeToTakePicture = true;
galleryAddPic();
}
Anyway, it takes too long
Your current algorithm looks like this:
Start with the photo in memory
Save the photo to disk, which is slow
Read the photo back in from disk to memory, which is slow
Rotate the reloaded photo
A more efficient approach would be:
Start with the photo in memory
Rotate the photo
BitmapFactory has decodeByteArray() to get a Bitmap back for rotation purposes.
I am creating a program that uses twice the takepicture function, like this:
mCamera.takePicture(null, null, mPicture);
But only once it enter the PictureCallback loop:
private PictureCallback mPicture = new PictureCallback(){
// Bitmap readyToGo;
#Override
public void onPictureTaken(byte[] data, Camera camera){
Log.d(TAG, "entrei no picture callback");
//-----OUT OF MEMORY ERROR
pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
mPreview.setDrawingCacheEnabled(true);
mPreview.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_AUTO);
BitmapFactory.Options options = new BitmapFactory.Options();
//options.inPurgeable = true;
//options.inInputShareable = true;
options.inJustDecodeBounds = true;
options.inSampleSize = 5;
options.inJustDecodeBounds = false;
Bitmap bitmap = mPreview.getDrawingCache();
//---------------------------------------------------
bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
//combine the two bitmaps!!!!-------------
Log.d("main", "antes overlay");
combination = overlay(bmp, bitmap);
Log.d("main", "depois overlay");
//------------------ROTATION---------------------
if(pictureFile == null)
{
Log.d(TAG, "Error creating media file, check storages permissions. ");
return;
}
try
{
ExifInterface exif = new ExifInterface(pictureFile.getAbsolutePath()); //Since API Level 5
String exifOrientation = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
Log.d("main", "exif orientation= "+exifOrientation);
FileOutputStream fos = new FileOutputStream(pictureFile);
Log.d(TAG, "ALO!!!");
combination.compress(CompressFormat.JPEG, 100, fos);//troquei bitmap por combination
fos.flush();
fos.close();
//------------------------------
clearBitmap(combination);
clearBitmap(bmp);
//------------------------------
}
catch(FileNotFoundException e)
{
Log.d(TAG, "File not found: "+e.getMessage());
}
catch(IOException e)
{
Log.d(TAG, "Error accessing file: "+e.getMessage());
}
}
};
Does anyobody know what happen, can I call it twice?
call thread to pause for 2 seconds and then recall it
or You can use your above code with this picture callback
public void takeSnapPhoto() {
camera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Parameters parameters = camera.getParameters();
int format = parameters.getPreviewFormat();
//YUV formats require more conversion
if (format == ImageFormat.NV21 || format == ImageFormat.YUY2 || format == ImageFormat.NV16) {
int w = parameters.getPreviewSize().width;
int h = parameters.getPreviewSize().height;
// Get the YuV image
YuvImage yuv_image = new YuvImage(data, format, w, h, null);
// Convert YuV to Jpeg
Rect rect = new Rect(0, 0, w, h);
ByteArrayOutputStream output_stream = new ByteArrayOutputStream();
yuv_image.compressToJpeg(rect, 100, output_stream);
byte[] byt = output_stream.toByteArray();
FileOutputStream outStream = null;
try {
// Write to SD Card
File file = createFileInSDCard(FOLDER_PATH, "Image_"+System.currentTimeMillis()+".jpg");
//Uri uriSavedImage = Uri.fromFile(file);
outStream = new FileOutputStream(file);
outStream.write(byt);
outStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
}
}); }
I've been fighting with this problem for a while. My camera activity is locked to portrait mode and due to other features on it - it must be portrait mode. After I take photo with my Camera and displays it it appears rotated. I found solution to handle this problem but it takes too much memory of weaker devices so after clicking "take photo" button I have to wait around 8 sec till it goes to next activity (PREVIEW ACTIVITY) while on my own Nexus 4 it works without lags and starts instantly. My current code looks like that:
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null){
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d("ABC", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("ABC", "Error accessing file: " + e.getMessage());
}
Bitmap bitmap = BitmapFactory.decodeFile(pictureFile.getAbsolutePath());
Matrix matrix = new Matrix();
if (currentCamera == BACK_CAMERA) {
matrix.postRotate(90);
} else {
matrix.postRotate(270);
matrix.preScale(1.0f, -1.0f);
}
Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
try {
FileOutputStream outStream = new FileOutputStream(pictureFile);
result.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
outStream.flush();
outStream.close();
} catch (FileNotFoundException e) {
Log.d("ABC", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("ABC", "Error accessing file: " + e.getMessage());
}
takenPhotoURL= pictureFile.getAbsolutePath();
Intent intent = new Intent(CameraActivity.this, PreviewActivity.class);
intent.putExtra("PhotoURI",takenPhotoURL);
intent.putExtra("voteID",voteId);
CameraActivity.this.startActivity(intent);
}
getOutputMediaFile is a method that generates directory in my device where photo should be saved. (I'm not adding photo to gallery yet). When you analyse the code I've posted above you can see that im using FileOutputStream twice. First time I just save photo in phone memory, second time I open it again, write it on rotated matrix and flush it. I think using FileOutputStream, saving -> opening -> saving -> closing -> opening -> saving - closing is slowing weaker devices. I would like to modify this metod somehow to make it more efficient. Please help me with that.
What I have tried till now is trying to delete first FileOutputStream and make everything at once like that:
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null){
return;
}
try {
FileOutputStream outStream = new FileOutputStream(pictureFile);
outStream.write(data);
Bitmap bitmap = BitmapFactory.decodeFile(pictureFile.getAbsolutePath());
Matrix matrix = new Matrix();
if (currentCamera == BACK_CAMERA) {
matrix.postRotate(90);
} else {
matrix.postRotate(270);
matrix.preScale(1.0f, -1.0f);
}
Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
result.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
outStream.flush();
outStream.close();
} catch (FileNotFoundException e) {
Log.d("ABC", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("ABC", "Error accessing file: " + e.getMessage());
}
takenPhotoURL= pictureFile.getAbsolutePath();
Intent intent = new Intent(CameraActivity.this, PreviewActivity.class);
intent.putExtra("PhotoURI",takenPhotoURL);
intent.putExtra("voteID",voteId);
CameraActivity.this.startActivity(intent);
}
but it doesnt work. Photo is displayed without any changes (nothing happens). And I've tried also Exif but it didn't have effect. Please help me make it more efficient and faster.
I am using the front camera to take a picture and display it in image view, but the image is not captured using frontface camera in samsung galaxy tab. Can anybody tell what the problem is? Even I had given set picture format. I used getoptimalpreview size for preview size. Can anybody tell me if I missed anything? Preview is showing properly but clicking 'take picture' background is black
mCamera = Camera.open();
Parameters params = mCamera.getParameters();
params.set("camera-id", 2);
params.setPictureFormat(PixelFormat.JPEG);
saving and setting display in imageview
public void onPictureTaken(byte[] data, Camera camera)
{
Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
imv.setImageBitmap(bmp);
String filename = "vijaypicture.jpg";
File pictureFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + filename);
try
{
FileOutputStream pfos = new FileOutputStream(pictureFile);
bmp.compress(CompressFormat.JPEG, 75, pfos);
pfos.flush();
pfos.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(String.format(
"/sdcard/test/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.d("", "onPictureTaken - wrote bytes: " + data.length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
Log.d("", "onPictureTaken - jpeg");
}
Hope that this helps, make manualy create a folder or use the mkdir command in your code to create the folder, and build a check if it already excists
I have an android app where I'm using the android camera in order to take photos.And after struglling a little bit I managed to have my picture where I want and how I want.The final problem is the quality of the image.
When my preview starts everything looks very clear and great but after taking the photo and showing the final result the image is not looking good at all.
Here is how my surfaceChanged() method looks like-where I'm setting some parameters:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.e(TAG, "surfaceChanged");
if (mPreviewRunning) {
mCamera.stopPreview();
}
Camera.Parameters p = mCamera.getParameters();
List<Size> sizes = p.getSupportedPictureSizes();
System.out.println("Lista de parametrii este urmatoarea:"+sizes);
Size size = sizes.get(7);
p.setPictureSize(size.width,size.height);
mCamera.setParameters(p);
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mCamera.startPreview();
mPreviewRunning = true;
}
Coudl someone tell what's the way to increase the quality of my photo.Thanks!
EDIT:
In activity A where the picture is taken I use a bundle to send the image to another activity B where I store it on the SDCARD.Here is how I do it:
Activity A:
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback(){
public void onPictureTaken(byte[] imageData, Camera c) {
if (imageData != null) {
Intent mIntent = new Intent();
Bundle b = new Bundle();
b.putByteArray("imageData", imageData);
Intent i = new Intent(mContext,ImageDisplayActivity.class);
i.putExtras(b);
startActivity(i);
setResult(FOTO_MODE, mIntent);
finish();
}
}
};
in activity B:
Bundle extras = getIntent().getExtras();
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 5;
byte[] imageData = extras.getByteArray("imageData");
Bitmap myImage = BitmapFactory.decodeByteArray(imageData , 0, imageData.length,options);
Matrix mat=new Matrix();
mat.postRotate(90);
bitmapResult = Bitmap.createBitmap(myImage, 0, 0, myImage.getWidth(),myImage.getHeight(), mat, true);
Canvas c = new Canvas(bitmapResult);
drawTextImage(bitmapResult);
I receive the picture I put it in a bitmap, I rotate it and draw a text on it in the method drawTextImage() .
After all this I store the bitmapResult on sdcard using this:
public static boolean StoreByteImage(Context mContext, Bitmap bitmap, int quality, String expName) {
FileOutputStream fileOutputStream = null;
String extStorageDirectory=Environment.getExternalStorageDirectory().toString();
File myNewFolder = new File(extStorageDirectory + newFolder);
if(myNewFolder.mkdirs())
{
myNewFolder.mkdir();
}
try {
//fileOutputStream = new FileOutputStream(sdImageMainDirectory.toString() +"/image.jpg");
fileOutputStream = new FileOutputStream(myNewFolder +"/"+expName+".jpg");
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
bitmap.compress(CompressFormat.JPEG, quality, bos);
bos.flush();
bos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
I ussually call it like this: StoreByteImage(getBaseContext(),bitmapResult,100,String.valueOf(value));
Thanks
I had this issue because auto-focus was disabled.
Try adding this permission to your Android Manifest:
<uses-feature android:name="android.hardware.camera.autofocus" />