I have an application that uses the Camera API to capture images. The implementation is contained within a CameraActivity class that is modeled after a number of examples that I have seen within this site. The application is currently running on thousands of phones correctly; however, today, I received a report from a HTC Desire Z user stating that my images are being captured as a series of vertical lines (unfortunately, I don't have enough points to post a picture, but have plenty to send if someone would like to see one). The image preview within my application and the image that I save are both distorted. The user has also confirmed that he is able to use his phone camera outside of my application without problem. I've attached the source for review.
Any help would be greatly appreciated.
public class CameraActivity extends Activity {
public static final int FOTO_MODE = 0;
private SurfaceView preview = null;
private SurfaceHolder previewHolder = null;
private Camera camera = null;
private boolean inPreview = false;
private String receiptFileName = null;
SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(previewHolder);
} catch (Throwable t) {
Log.e("PreviewDemo-surfaceCallback", "Exception in setPreviewDisplay()", t);
Toast.makeText(CameraActivity.this, t.getMessage(), Toast.LENGTH_LONG).show();
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
camera.setParameters(parameters);
camera.startPreview();
inPreview = true;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// no-op
}
};
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] imageData, Camera c) {
if (imageData != null) {
StoreByteImage(CameraActivity.this, imageData, 50, "ImageName");
camera.startPreview();
Intent resultIntent = new Intent();
resultIntent.putExtra(getString(R.string.receiptFileName), receiptFileName);
setResult(FOTO_MODE, resultIntent);
finish();
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.camera_preview);
receiptFileName = getIntent().getStringExtra(getString(R.string.receiptFileName));
ImageView shutterButton = (ImageView) findViewById(R.id.shutterButton);
shutterButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
takePicture();
}
});
shutterButton.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
focusOnly();
return false;
}
});
preview = (SurfaceView) findViewById(R.id.surface_camera);
previewHolder = preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void onResume() {
super.onResume();
camera = Camera.open();
}
@Override
public void onPause() {
if (inPreview) {
camera.stopPreview();
}
camera.release();
camera = null;
inPreview = false;
super.onPause();
}
private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return result;
}
private void focusOnly() {
String focusMode = camera.getParameters().getFocusMode();
if (focusMode != null
&& (focusMode.equals(Camera.Parameters.FOCUS_MODE_AUTO) || focusMode
.equals(Camera.Parameters.FOCUS_MODE_MACRO))) {
Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
}
};
camera.autoFocus(autoFocusCallback);
}
}
private void takePicture() {
camera.takePicture(null, mPictureCallback, mPictureCallback);
}
private boolean StoreByteImage(Context mContext, byte[] imageData, int quality, String expName) {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
FileOutputStream fileOutputStream = null;
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bMap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
Matrix mat = new Matrix();
mat.postRotate(90);
Bitmap myImage = Bitmap.createBitmap(bMap, 0, 0, bMap.getWidth(), bMap.getHeight(), mat, true);
File path = new File(Environment.getExternalStorageDirectory() + ExpenseIt.SD_CARD_PATH_EXTENSION);
path.mkdirs();
fileOutputStream = new FileOutputStream(path + "/" + determineReceiptName());
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
myImage.compress(CompressFormat.JPEG, quality, bos);
bos.flush();
bos.close();
} catch (Exception e) {
FailureDialogFactory.getInstance().handleFailure(this, "Failure storing camera image.", e);
}
} else {
FailureDialogFactory.getInstance().handleFailure(this,
"Unable capture receipts while SD card is not available or phone is connected to computer.", null);
}
return true;
}
private String determineReceiptName() {
if (receiptFileName == null) {
receiptFileName = Calendar.getInstance().getTimeInMillis() + ".jpg";
}
return receiptFileName;
}