I am using Camera in my app to take pictures of ID cards, I have a rectangular overlay to which image will be cropped. issue is that the image quality is reduced once the image is captured.
I am unable to figure out where exactly it is happening. In cutImage method, I am cutting the image but I don't think I am doing anything to the resolution of the image there.
Can any one suggest where the quality might be going down.
takePicture is called when the user clicks to take the picture.
Once the picture is taken there is a button 'use picture' that is when usePicture is called.
cutImage method is used to crop the image based on the preview.
any suggestions on how to stop the resolution from going down will be very very helpful
protected void takePicture() {
Log.e(TAG, "takePicture started");
if(null == cameraDevice) {
Log.e(TAG, "cameraDevice is null");
return;
}
try {
ImageReader reader = ImageReader.newInstance(textureViewWidth, textureViewHeight, 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 = getActivity().getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
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);
takenPictureBytes = bytes;
Log.d(TAG, "takenPictureBytes length - " + takenPictureBytes.length);
} catch (Exception e) {
Log.d(TAG, " onImageAvailable exception ");
e.printStackTrace();
} finally {
if (image != null) {
Log.d(TAG, " image closing");
image.close();
}
}
}
};
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Log.d(TAG, "takePicture - camera capture session");
switchPanels(true);
progress.setVisibility(View.GONE);
}
};
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
} catch (CameraAccessException e) {
Log.d(TAG, "takePicture - onConfigured- camera access exception ");
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(CameraCaptureSession session) {
Log.d(TAG, "takePicture - onConfigureFailed");
}
}, mBackgroundHandler);
} catch (CameraAccessException e) {
Log.d(TAG, "takePicture - CameraAccessException ");
e.printStackTrace();
}
}
private void usePicture() {
Log.d(TAG, "usePicture - started ");
if(null != takenPictureBytes ){
try{
String imagePath = null;
Bitmap bitmap = BitmapFactory.decodeByteArray(takenPictureBytes, 0, takenPictureBytes.length);
int bitmapByteCountUsePic = byteSizeOf(bitmap);
Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
if (isFrameMode) {
float withRatio = (float) rotatedBitmap.getWidth() / (float) textureViewWidth;
float heightRatio = (float) rotatedBitmap.getHeight() / (float) textureViewHeight;
Bitmap newImage = cutImage(rotatedBitmap, (int) (photoFrameView.getWidth() * withRatio), (int) (photoFrameView.getHeight() * heightRatio), withRatio);
int bitmapByteCountNewImage = byteSizeOf(newImage);
imagePath = saveBitmap(newImage);
} else {
imagePath = saveBitmap(rotatedBitmap);
}
TakePhotoFragment.TakePhotoFragmentEvent takePhotoFragmentEvent = new TakePhotoFragment.TakePhotoFragmentEvent();
takePhotoFragmentEvent.setImagePath(imagePath);
// send rxjava
//pop backstack
RxBus.getInstance().post(takePhotoFragmentEvent);
getActivity().getSupportFragmentManager().popBackStack();
}catch (Exception e){
Log.d(TAG, "usePicture - exception ");
e.printStackTrace();
}
}else{
Log.d(TAG, "usePicture - takenPictureBytes is null");
DialogUtil.showErrorSnackBar(getView(), R.string.retake_photo );
}
}
public Bitmap cutImage(final Bitmap bitmap, final int pixepWidth, final int pixelsHeight, float widthRatio) {
int bitmapByteCountCutImage = byteSizeOf(bitmap);
Bitmap output = createBitmap(pixepWidth, pixelsHeight, Bitmap.Config.ARGB_8888);
Bitmap original = bitmap;
final Paint paint = new Paint();
Canvas canvas = new Canvas(output);
int padding = (int) ((float) getResources().getDimensionPixelSize(R.dimen.double_padding) * widthRatio);
Rect rect = new Rect(padding, (original.getHeight() - pixelsHeight) / 2, padding + pixepWidth, original.getHeight() - (original.getHeight() - pixelsHeight) / 2);
final RectF cutedRect = new RectF(0, 0, pixepWidth, pixelsHeight);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawBitmap(original, rect, cutedRect, paint);
return output;
}
private String saveBitmap(Bitmap bitmap) {
File pictureFileDir = getDir();
if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {
Toast.makeText(getActivity(), "Can't create directory to save image.", Toast.LENGTH_LONG).show();
return null;
}
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmssSSS");
String date = dateFormat.format(new Date());
String photoFile = "Picture_" + date + ".jpg";
String filename = pictureFileDir.getPath() + File.separator + photoFile;
File pictureFile = new File(filename);
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(stream.toByteArray());
fos.close();
return pictureFile.getAbsolutePath();
} catch (Exception error) {
Log.d(TAG, "File" + filename + "not saved: " + error.getMessage());
}
return null;
}
You are changing the bitmap size/resolution in this code:
float withRatio = (float) rotatedBitmap.getWidth() / (float) textureViewWidth;
float heightRatio = (float) rotatedBitmap.getHeight() / (float) textureViewHeight;
Bitmap newImage = cutImage(rotatedBitmap, (int) (photoFrameView.getWidth() * withRatio), (int) (photoFrameView.getHeight() * heightRatio), withRatio);
int bitmapByteCountNewImage = byteSizeOf(newImage);
imagePath = saveBitmap(newImage);
Put in a breakpoint and see what the new heightRatio and widthRatio are, and what the photoFrameView.getWidth() * withRatio value comes out to. I think you will find it is small compared to the original image. I'm not sure why you are calculating the Ratios with the textureViewWidth/Height, you shouldn't have to do that. Whatever you are displaying the image in should be able to 'Fill' without having to change the size of the underlying bitmap, and thus losing resolution.
You might check out this method:
rawBitmap = ((BitmapDrawable)imageToLoad.getDrawable()).getBitmap();
theBitmap = Bitmap.createScaledBitmap(rawBitmap, 285, 313, false);
Related
I am working in an application in which I need to capture images in LANDSCAPE mode. The functionality is working fine but the problem I am getting is, when ever the Image is captured, I am getting extra side of captured image. I am getting this problem when I am using transform method (Code is below). Please tell me how do I remove extra side of image. Please look at the images below
1) Before Capturing Image
2) After Capturing Image
Code for camera landscape mode
private void transformImage(int viewWidth, int viewHeight) {
if (null == textureView || null == previewSize) {
return;
}
int rotation = getWindowManager().getDefaultDisplay().getRotation();
matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, previewSize.getHeight(), previewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / previewSize.getHeight(),
(float) viewWidth / previewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
} else if (Surface.ROTATION_180 == rotation) {
matrix.postRotate(180, centerX, centerY);
}
textureView.setTransform(matrix);
}
Code for Capturing Images
void getPicture() {
if (cameraDevice == null) {
return;
}
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
assert manager != null;
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
if (characteristics != null) {
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
}
int width = 640, height = 480;
if (jpegSizes != null && jpegSizes.length > 0) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
final 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);
int rotation = getWindowManager().getDefaultDisplay().getRotation();
capturebuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATION.get(rotation));
ImageReader.OnImageAvailableListener imageAvailableListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader reader) {
Image image = null;
try {
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
bytes = new byte[buffer.capacity()];
buffer.get(bytes);
save(bytes);
} catch (Exception ee) {
Log.e("ImageReader Error ", ee.getMessage());
} finally {
if (image != null)
image.close();
}
}
void save(byte[] bytes) {
File file12 = getOutputMediaFile();
OutputStream outputStream = null;
try {
assert file12 != null;
//file12 = new Compressor(VehicleEpaCamera.this).compressToFile(file12);
outputStream = new FileOutputStream(file12);
outputStream.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (outputStream != null)
outputStream.close();
} catch (Exception e) {
}
}
}
};
reader.setOnImageAvailableListener(imageAvailableListener, handler);
previewSSession = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
}
#Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
try {
session.stopRepeating();
} catch (CameraAccessException e) {
Toast.makeText(VehicleEpaCamera.this, e.getMessage(), Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
if (bytes != null) {
callCloudVision(bitmap, feature);
} else {
Toast.makeText(VehicleEpaCamera.this, "Something went wrong", Toast.LENGTH_SHORT).show();
getPicture();
}
}
};
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession session) {
try {
session.capture(capturebuilder.build(), previewSSession, handler);
} catch (Exception e) {
}
}
#Override
public void onConfigureFailed(CameraCaptureSession session) {
}
}, handler);
} catch (Exception e) {
}
}
my apps have feature set photo profile, but when upload an image from gallery to server the image automatic rotated 90 degree, this issue appear only for portrait image, in landscape image running well, I already add crop feature but it doesn't help, here is my code to update profile image:
private void updateProfile(){
// multipart
MultipartBody.Part _file = null;
if(proPicPath != null){
// ini progress listener
ProgressRequestBody.ProgressListener progressListener = new ProgressRequestBody.ProgressListener() {
#Override
public void transferred(final int num, long transferred, long totalSize) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
try {
dialogUpload.setMessage("Updating "+ num + "%");
}catch (NullPointerException ne){
ne.printStackTrace();
}
}
});
}
};
File file = new File(proPicPath);
// init request body
ProgressRequestBody requestFileBody = new ProgressRequestBody(file, "multipart/form-data", progressListener);
_file = MultipartBody.Part.createFormData("caller_pic", file.getName(), requestFileBody);
}
// set request body
RequestBody _caller_id = RequestBody.create(MediaType.parse("text/plain"), own.caller_id);
RequestBody _name = null;
if(!etUserName.getText().toString().isEmpty())
_name = RequestBody.create(MediaType.parse("text/plain"), etUserName.getText().toString());
RequestBody _email = null;
if(!etUserEmail.getText().toString().isEmpty())
_email = RequestBody.create(MediaType.parse("text/plain"), etUserEmail.getText().toString());
Call<APIResponse<ContactItem>> call = ServicesFactory.getService().updateProfile(_caller_id, _name, _email, _file);
call.enqueue(new Callback<APIResponse<ContactItem>>() {
#Override
public void onResponse(Call<APIResponse<ContactItem>> call, Response<APIResponse<ContactItem>> response) {
dialogUpload.dismiss();
dialogUpload = null;
if(response.isSuccessful() && response.body().isSuccessful()){
proPicPath = null;
ContactItem updated = response.body().data;
// save to session and update local variable
own = SessionManager.saveProfile(ProfileActivity.this, updated);
// update ui
setUserInfo();
checkProfileChanged();
toast("Update profile success");
}
else{
toast("Update profile failed");
}
}
#Override
public void onFailure(Call<APIResponse<ContactItem>> call, Throwable t) {
dialogUpload.dismiss();
dialogUpload = null;
toast("Update profile failed");
}
});
}
I got exactly the same issue, I solve it with this :
int IMAGE_UPLOAD_MAX_COMPRESSION = 75;
Bitmap mSelectedImage;
try {
mSelectedImage = MediaStore.Images.Media.getBitmap(this.getContentResolver(), Uri.parse("file:" + mCurrentPhotoPath));
mSelectedImage = PictureOrientation.bitmapFromUri(EditProfileActivity.this, Uri.parse("file:" + mCurrentPhotoPath));
OutputStream os = new FileOutputStream(mCurrentPhotoPath);
mSelectedImage.compress(Bitmap.CompressFormat.JPEG, IMAGE_UPLOAD_MAX_COMPRESSION, os);
os.flush();
os.close();
} catch (Exception ex) {
ex.printStackTrace();
}
The interesting part for you is here
PictureOrientation.bitmapFromUri(EditProfileActivity.this, Uri.parse("file:" + mCurrentPhotoPath));
This is the PictureOrientation class :
public class PictureOrientation {
public static Bitmap bitmapFromUri(Context context, Uri photoUri)
throws FileNotFoundException, IOException {
InputStream is = context.getContentResolver().openInputStream(photoUri);
BitmapFactory.Options dbo = new BitmapFactory.Options();
dbo.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, dbo);
is.close();
int rotatedWidth, rotatedHeight;
int orientation = 0;
if (photoUri.toString().contains("content:/")) {
orientation = getOrientation(context, photoUri);
} else {
int orientationFormExif = getOrientationFromExif(photoUri, context);
orientation = decodeExifOrientation(orientationFormExif);
}
if (orientation == 90 || orientation == 270) {
rotatedWidth = dbo.outHeight;
rotatedHeight = dbo.outWidth;
} else {
rotatedWidth = dbo.outWidth;
rotatedHeight = dbo.outHeight;
}
Bitmap srcBitmap = readScaledBitmapFromUri(photoUri, context,
rotatedWidth, rotatedHeight);
srcBitmap = setProperOrientation(orientation, srcBitmap);
return srcBitmap;
}
private static int getOrientation(Context context, Uri photoUri) {
/* it's on the external media. */
Cursor cursor = context.getContentResolver().query(photoUri,
new String[]{MediaStore.Images.ImageColumns.ORIENTATION},
null, null, null);
if (cursor.getCount() != 1) {
return -1;
}
cursor.moveToFirst();
return cursor.getInt(0);
}
private static int getOrientationFromExif(Uri imageUri, Context context) {
int orientation = -1;
File imageFile = new File(imageUri.getPath());
try {
ExifInterface exif;
exif = new ExifInterface(imageFile.getAbsolutePath());
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
} catch (IOException e) {
e.printStackTrace();
}
return orientation;
}
private static int decodeExifOrientation(int orientation) {
switch (orientation) {
case ExifInterface.ORIENTATION_NORMAL:
orientation = 0;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
orientation = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
orientation = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
orientation = 270;
break;
default:
break;
}
return orientation;
}
private static Bitmap readScaledBitmapFromUri(Uri photoUri, Context context, int width, int height)
throws FileNotFoundException, IOException {
InputStream is;
Bitmap srcBitmap;
is = context.getContentResolver().openInputStream(photoUri);
if (width > EditProfileActivity.IMAGE_WIDTH || height > EditProfileActivity.IMAGE_HEIGHT) {
float ratio = calculateScaleRatio(width, height);
srcBitmap = readRoughScaledBitmap(is, ratio);
ratio = calculateScaleRatio(srcBitmap.getWidth(),
srcBitmap.getHeight());
srcBitmap = scaleBitmap(srcBitmap, ratio);
} else {
srcBitmap = BitmapFactory.decodeStream(is);
}
is.close();
return srcBitmap;
}
private static float calculateScaleRatio(int width, int height) {
float widthRatio = ((float) width) / ((float) EditProfileActivity.IMAGE_WIDTH);
float heightRatio = ((float) height) / ((float) EditProfileActivity.IMAGE_HEIGHT);
float maxRatio = Math.max(widthRatio, heightRatio);
return maxRatio;
}
private static Bitmap readRoughScaledBitmap(InputStream is, float maxRatio) {
Bitmap result;
// Create the bitmap from file
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = (int) maxRatio;
result = BitmapFactory.decodeStream(is, null, options);
return result;
}
private static Bitmap scaleBitmap(Bitmap bitmap, float ratio) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Matrix matrix = new Matrix();
matrix.postScale(1f / ratio, 1f / ratio);
Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, width, height,
matrix, true);
return result;
}
private static Bitmap setProperOrientation(int orientation, Bitmap srcBitmap) {
if (orientation > 0) {
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0,
srcBitmap.getWidth(), srcBitmap.getHeight(), matrix, true);
}
return srcBitmap;
}
}
This class look the exif orientation of the picture and rotate it.
I want exactly the functionality of Camera (Like Single and Batch(Multiple Photos at a time)) in the following app:
https://play.google.com/store/apps/details?id=com.thegrizzlylabs.geniusscan.free&hl=en
I have implemented Successfully this. But, my question is, I have implemented this functionality with SurfaceView. When I capture photos from camera, its blurred when compared to the Genius Scan App.
Could anyone please let me know how exactly i can achieve this functionality without getting blurred.
NOTE: Capturing Multiple Photos
private void takeImage() {
camera.takePicture(null, null, new PictureCallback() {
private File imageFile;
#Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
// convert byte array into bitmap
Bitmap loadedImage = null;
Bitmap rotatedBitmap = null;
loadedImage = BitmapFactory.decodeByteArray(data, 0,
data.length);
// rotate Image
Matrix rotateMatrix = new Matrix();
rotateMatrix.postRotate(rotation);
rotatedBitmap = Bitmap.createBitmap(loadedImage, 0, 0,
loadedImage.getWidth(), loadedImage.getHeight(),
rotateMatrix, false);
String state = Environment.getExternalStorageState();
File folder = null;
if (state.contains(Environment.MEDIA_MOUNTED)) {
folder = new File(Environment
.getExternalStorageDirectory() + "/Demo");
} else {
folder = new File(Environment
.getExternalStorageDirectory() + "/Demo");
}
boolean success = true;
if (!folder.exists()) {
success = folder.mkdirs();
}
if (success) {
java.util.Date date = new java.util.Date();
imageFile = new File(folder.getAbsolutePath()
+ File.separator
+ new Timestamp(date.getTime()).toString()
+ "Image.jpg");
imageFile.createNewFile();
} else {
Toast.makeText(getBaseContext(), "Image Not saved",
Toast.LENGTH_SHORT).show();
return;
}
ByteArrayOutputStream ostream = new ByteArrayOutputStream();
// save image into gallery
rotatedBitmap.compress(CompressFormat.JPEG, 100, ostream);
FileOutputStream fout = new FileOutputStream(imageFile);
fout.write(ostream.toByteArray());
fout.close();
ContentValues values = new ContentValues();
values.put(Images.Media.DATE_TAKEN,
System.currentTimeMillis());
values.put(Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.MediaColumns.DATA,
imageFile.getAbsolutePath());
CameraDemoActivity.this.getContentResolver().insert(
Images.Media.EXTERNAL_CONTENT_URI, values);
if (mSingleView.getVisibility() == View.VISIBLE) {
btnDoneClicked();
} else {
}
mArrayUri.add(Uri.fromFile(imageFile));
if (mBatchView.getVisibility() == View.VISIBLE) {
batchClickCount++;
mtxtCapturedClicks.setText(String.valueOf(batchClickCount));
} else {
batchClickCount = 0;
mtxtCapturedClicks.setText("");
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public static Bitmap scaleBitmap(Bitmap bitmap, int newWidth, int newHeight) {
Bitmap scaledBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
float scaleX = newWidth / (float) bitmap.getWidth();
float scaleY = newHeight / (float) bitmap.getHeight();
float pivotX = 0;
float pivotY = 0;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(scaleX, scaleY, pivotX, pivotY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bitmap, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG));
return scaledBitmap;
}
Try this function to improve the image quality
I am working on an image processing app and I need to divide taken photo into four regions, but using BitmapFactoy takes too much resource and time and slows me down, I would like to do this using raw byte[] data that public void onPictureTaken(byte[] data, Camera camera) gives me.
Right now this is what I do and I want to improve it to use byte[] to speed it up:
public void onPictureTaken(byte[] data, Camera camera) {
new AsyncImageAnalyzer(data).execute();
data = null;
}
public AsyncImageAnalyzer(byte[] d) {
mData = d;
surfaceView = null;
}
#Override
protected Void doInBackground(Void... params) {
FileOutputStream fos2 = null;
try {
String fileName = Long.toString(Calendar.getInstance().getTimeInMillis())+".jpg";
String storageState = Environment.getExternalStorageState();
if (storageState.equals(Environment.MEDIA_MOUNTED)) {
File file = new File(/*"/sdcard/XXX"*/Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator+"XXX",
fileName);
/*file.createNewFile();*/
fos2 = new FileOutputStream(file);
fos2.write(mData,0,mData.length);
fos2.flush();
fos2.close();
/*fos2.write(mData);*/
/*fos2.close();*/
if(extrasReceived.equals("1")){
spe.putString("FirstPicPath","/"+fileName).commit();
}else {
spe.putString("SecondPicPath","/"+fileName).commit();
}
}
} catch (Exception e) {
e.printStackTrace();
Log.e("ISA exception",e.getMessage() );
}finally {
try {
if (fos2 != null) {
fos2.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = sp.getInt("compression_ratio",1);
bitmap = BitmapFactory.decodeByteArray(mData, 0, mData.length,options);
mData = null;
t1G = Bitmap.createBitmap(bitmap, 0, (bitmap.getHeight() / 2) - 1, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
t2G = Bitmap.createBitmap(bitmap, (bitmap.getWidth() / 2) - 1, (bitmap.getHeight() / 2) - 1, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
t1R = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
t2R = Bitmap.createBitmap(bitmap, (bitmap.getWidth() / 2) - 1, 0, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
try {
t2RtoInt = getDominantColor(t2R);
t1RtoInt = getDominantColor(t1R);
t1GtoInt = getDominantColor(t1G);
t2GtoInt = getDominantColor(t2G);
} catch (Exception e) {
e.printStackTrace();
Log.e("exception", e.getMessage());
}
return null;
}
Also any advice for me that causes speed up in these operations would be appreciated.
Have you ever think about BitmapRegionDecoder (Currently only the JPEG and PNG formats are supported)? If you develop your app with API level 10 and up, you could use this API to speed up the large bitmap processing.
boolean isShareable = false;
try {
InputStream is = new FileInputStream("/mnt/sdcard/test.png");
Rect rect = new Rect();
BitmapFactory.Options options = new BitmapFactory.Options();
BitmapRegionDecoder.newInstance(is, isShareable).decodeRegion(rect, options);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I am following the tutorial here to take picture with other app AND with customized SurfaceView.
When take picture with SurfaceView, the picture is taken successfully (I quit my app and saw the result image file does exist in file manager, and the image content is correct.), but the picture cannot show correctly in my app. The ImageView shows nothing.
My code is like this:
public void onPictureTaken(byte[] data, Camera camera) {
try {
File file = Utils.getOutputMediaFile(Utils.MediaFileType.Image);
FileOutputStream os = new FileOutputStream(file);
os.write(data);
os.flush();
os.close();
final Uri uri = Uri.fromFile(file);
showImage(uri);
} catch (FileNotFoundException e) {
Log.d(TAG, "onPictureTaken, e=" + e);
} catch (IOException e) {
Log.d(TAG, "onPictureTaken, e=" + e);
}
camera.startPreview();
}
private void showImage(Uri imageFileUri) {
int w = mContentContainer.getWidth();
int h = mContentContainer.getHeight();
Bitmap bmp = Utils.loadBitmapFromFile(imageFileUri.getPath(), w, h);
mImageView.setImageBitmap(bmp);
mStatusTextView.setText("take photo: succcess");
}
public static Bitmap loadBitmapFromFile(String filename, int maxWidth, int maxHeight) {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filename, opt);
Log.d(TAG, "loadBitmapFromFile, w=" + opt.outWidth + ", h=" + opt.outHeight);
int widthRatio = (int) Math.ceil(opt.outWidth / maxWidth);
int heightRatio = (int) Math.ceil(opt.outHeight / maxHeight);
if (widthRatio > 1 || heightRatio > 1) {
if (widthRatio > heightRatio) {
opt.inSampleSize = widthRatio;
} else {
opt.inSampleSize = heightRatio;
}
}
opt.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeFile(filename, opt);
Log.d(TAG, "loadBitmapFromFile, bmp=" + bmp);
return bmp;
}
From log, I saw the width and height is correctly loaded from file, and bmp is not null, but the ImageView is just empty.
Strange is, if my app firstly take a photo and show the photo with showImage() (the ImageView shows photo correctly), then after that, take phone with SurfaceView and show with showImage(), the photo shows correctly. But if directly take phone with SurfaceView and showImage(), the ImageView is empty.
Any comments about why the ImageView is empty? Thanks.
Try (see the comments):
private void showImage(Uri imageFileUri) {
int w = mContentContainer.getWidth();
int h = mContentContainer.getHeight();
Bitmap bmp = Utils.loadBitmapFromFile(imageFileUri.getPath(), w, h);
mImageView.requestLayout(); //try to request the layout first
mImageView.setImageBitmap(bmp);
//if its still not working try to call invalidate() method here
mStatusTextView.setText("take photo: succcess");
}