之前處理相機模塊的時候,遇到了一個問題,就是調用系統的camera的時候在拍照預覽界面的時候看到的照片是變形的。不曉得大家有沒有和我遇到一樣的問題,后來發現是我的布局界面沒有按對應的比例進行縮放導致的。后來參考了系統camera中的代碼解決了這個問題,特此記錄下來。每部手機中設置了好幾組預覽圖片的尺寸、以及實際圖片的尺寸。只有當預覽圖的尺寸比例和實際圖片的比例相同的時候就不會出現變形的情況。下面一組數據是我測試中記錄的一組數據:
02-09 19:00:40.831: D/tag(27507): pictureSizeValueString : 1280x960,1600x1200,2048x1536,2592x1456,2592x1936
02-09 19:00:40.831: D/tag(27507): previewSizeValueString : 176x144,320x240,352x288,640x480,720x480,720x576,848x480,1280x720
上面紅色部分標記的都是具有相同比例的尺寸,都為4:3,而其他比例卻不盡相同。故我們只要在初始化camera的時候給其設置好相同比例的預覽圖尺寸和實際圖的尺寸,並且設置你的SurfaceView或者VideoView的尺寸比例相同就行了。但是要注意的是:魅族手機貌似取不到這些值。
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
//設置參數
mCamera = Camera.open();
//攝像頭畫面顯示在Surface上
mCamera.setPreviewDisplay(surfaceHolder);
Parameters parameters = mCamera.getParameters();
} catch (IOException e) {
if (mCamera != null) mCamera.release();
mCamera = null;
}
if (mCamera == null) {
finish();
return ;
}
updateCameraParameters();
mCamera.startPreview();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
try {
//攝像頭畫面顯示在Surface上
mCamera.setPreviewDisplay(surfaceHolder);
updateCameraParameters();
mCamera.startPreview();
} catch (IOException e) {
if (mCamera != null) mCamera.release();
mCamera = null;
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
//關閉預覽
mCamera.release();
//釋放資源
}
private void updateCameraParameters() {
if (mCamera != null) {
Camera.Parameters p = mCamera.getParameters();
long time = new Date().getTime();
p.setGpsTimestamp(time);
Size pictureSize = findBestPictureSize(p);
p.setPictureSize(pictureSize.width, pictureSize.height);
// Set the preview frame aspect ratio according to the picture size.
Size size = p.getPictureSize();
PreviewFrameLayout frameLayout = (PreviewFrameLayout) findViewById(R.id.frame_layout);
frameLayout.setAspectRatio((double) size.width / size.height);
Size previewSize = findBestPreviewSize(p);
p.setPreviewSize(previewSize.width,previewSize.height);
mCamera.setParameters(p);
int supportPreviewWidth = previewSize.width;
int supportPreviewHeight = previewSize.height;
int srcWidth = getScreenWH().widthPixels;
int srcHeight = getScreenWH().heightPixels;
int width = Math.min(srcWidth, srcHeight);
int height = width * supportPreviewWidth / supportPreviewHeight ;
mSur.setLayoutParams(new FrameLayout.LayoutParams(height, width));//
}
}
private Size findBestPictureSize(Camera.Parameters parameters) {
int diff = Integer.MIN_VALUE;
String pictureSizeValueString = parameters.get("picture-size-values");
// saw this on Xperia
if (pictureSizeValueString == null) {
pictureSizeValueString = parameters.get("picture-size-value");
}
if(pictureSizeValueString == null) {
return mCamera.new Size(getScreenWH().widthPixels,getScreenWH().heightPixels);
}
Log.d("tag", "pictureSizeValueString : " + pictureSizeValueString);
int bestX = 0;
int bestY = 0;
for(String pictureSizeString : COMMA_PATTERN.split(pictureSizeValueString))
{
pictureSizeString = pictureSizeString.trim();
int dimPosition = pictureSizeString.indexOf('x');
if(dimPosition == -1){
Log.e(TAG, "Bad pictureSizeString:"+pictureSizeString);
continue;
}
int newX = 0;
int newY = 0;
try{
newX = Integer.parseInt(pictureSizeString.substring(0, dimPosition));
newY = Integer.parseInt(pictureSizeString.substring(dimPosition+1));
}catch(NumberFormatException e){
Log.e(TAG, "Bad pictureSizeString:"+pictureSizeString);
continue;
}
Point screenResolution = new Point (getScreenWH().widthPixels,getScreenWH().heightPixels);
int newDiff = Math.abs(newX - screenResolution.x)+Math.abs(newY- screenResolution.y);
if(newDiff == diff)
{
bestX = newX;
bestY = newY;
break;
} else if(newDiff > diff){
if((3 * newX) == (4 * newY)) {
bestX = newX;
bestY = newY;
diff = newDiff;
}
}
}
if (bestX > 0 && bestY > 0) {
return mCamera.new Size(bestX, bestY);
}
return null;
}
private Size findBestPreviewSize(Camera.Parameters parameters) {
String previewSizeValueString = null;
int diff = Integer.MAX_VALUE;
previewSizeValueString = parameters.get("preview-size-values");
if (previewSizeValueString == null) {
previewSizeValueString = parameters.get("preview-size-value");
}
if(previewSizeValueString == null) { // 有些手機例如m9獲取不到支持的預覽大小 就直接返回屏幕大小
return mCamera.new Size(getScreenWH().widthPixels,getScreenWH().heightPixels);
}
Log.d("tag", "previewSizeValueString : " + previewSizeValueString);
int bestX = 0;
int bestY = 0;
for(String prewsizeString : COMMA_PATTERN.split(previewSizeValueString))
{
prewsizeString = prewsizeString.trim();
int dimPosition = prewsizeString.indexOf('x');
if(dimPosition == -1){
Log.e(TAG, "Bad prewsizeString:"+prewsizeString);
continue;
}
int newX = 0;
int newY = 0;
try{
newX = Integer.parseInt(prewsizeString.substring(0, dimPosition));
newY = Integer.parseInt(prewsizeString.substring(dimPosition+1));
}catch(NumberFormatException e){
Log.e(TAG, "Bad prewsizeString:"+prewsizeString);
continue;
}
Point screenResolution = new Point (getScreenWH().widthPixels,getScreenWH().heightPixels);
int newDiff = Math.abs(newX - screenResolution.x)+Math.abs(newY- screenResolution.y);
if(newDiff == diff)
{
bestX = newX;
bestY = newY;
break;
} else if(newDiff < diff){
if((3 * newX) == (4 * newY)) {
bestX = newX;
bestY = newY;
diff = newDiff;
}
}
}
if (bestX > 0 && bestY > 0) {
return mCamera.new Size(bestX, bestY);
}
return null;
}
protected DisplayMetrics getScreenWH() {
DisplayMetrics dMetrics = new DisplayMetrics();
dMetrics = this.getResources().getDisplayMetrics();
return dMetrics;
}