【发布时间】:2015-04-04 14:33:14
【问题描述】:
我正在尝试像 instagram 一样制作图像捕捉屏幕。
这是我的SurfaceView 代码
<SquareFrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/camLayout"
/>
SquareFrameLayout with measure overridden
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
这是我的SurfaceView 班级:
import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.List;
public class CameraView extends SurfaceView implements SurfaceHolder.Callback
{
private static final String TAG = "CameraPreview";
private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
public CameraView(Context context, Camera camera)
{
super(context);
mContext = context;
mCamera = camera;
// supported preview sizes
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
for(Camera.Size str: mSupportedPreviewSizes)
Log.e(TAG, str.width + "/" + str.height);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// empty. surfaceChanged will take care of stuff
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + h);
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or reformatting changes here
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
if(mCamera.getParameters().isZoomSupported())
mCamera.getParameters().setZoom(0);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
float ratio;
if(mPreviewSize.height >= mPreviewSize.width)
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
else
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
// One of these methods should be used, second method squishes preview slightly
setMeasuredDimension(width, (int) (width * ratio));
// setMeasuredDimension((int) (width * ratio), height);
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) h / w;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.height / size.width;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
这是结果。我的图片有点放大了。我不知道该怎么做才能使它相似。
【问题讨论】:
-
我怀疑这是与缩放相关的问题。这很可能是因为您在此处选择了错误的预览大小,而这可能是因为您的
camLayot(这是CameraView的容器)具有正方形的形式。尝试用普通的FrameLayout重写你的代码,看看它是否有所作为。 -
@aga 好的,我让应用匹配父级而不是方形视图,但 instagram 确实在一秒钟内捕获图像。但是,如果我要裁剪图像,则需要时间。 insta 怎么处理得这么快。
-
如果不查看专有的 Instagram 源代码就很难判断。也许您可以尝试反编译他们的应用程序并查看源代码。
-
也许他们正在使用支持的图片尺寸,该尺寸尽可能接近裁剪后的图像,因此裁剪效果非常快。
-
@aga 我现在已经确认,我的应用具有精确的相机分辨率和缩放,就像 android 相机应用一样。然而 instagram 奇怪地显示缩小的图像。预览尺寸和表面支架尺寸,我都试过了,不管是全屏还是方形都没有关系。它们仍然像 android 相机应用程序,但不像 instagram :((((
标签: java android android-camera instagram