相机预览未全屏显示(显示在框中)

2024-02-02

我想使用自定义相机拍摄比预览尺寸更小的照片,我听说保持纵横比非常重要。我已经使用了PreviewFrameLayout in AOSP ICS https://android.googlesource.com/platform/packages/apps/Camera/+/ics-factoryrom-2-release/src/com/android/camera/PreviewFrameLayout.java我发现SurfaceView只显示在盒子中活动的中心,并没有填充整个屏幕。

public class PreviewFrameLayout extends RelativeLayout{

static final String TAG="PreviewFrameLayout";
public interface OnSizeChangedListener
{
    public void onSizeChanged(int w,int h);
}

OnSizeChangedListener mListener;

public void setOnSizeChangedListener(OnSizeChangedListener listener)
{
    mListener=listener;
}

private double mAspectRatio=4.0/3.0;

public PreviewFrameLayout(Context c,AttributeSet attrs)
{
    super(c,attrs);
}

public void setAspectRatio(double ratio)
{
    if(ratio<=0.0)
        throw new IllegalArgumentException();
    if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT)
        ratio=1/ratio;
    if(mAspectRatio!=ratio)
    {
        mAspectRatio=ratio;
        requestLayout();
    }
}

@Override
protected void onMeasure(int widthSpec,int heightSpec)
{
    int previewWidth=MeasureSpec.getSize(widthSpec);
    int previewHeight=MeasureSpec.getSize(heightSpec);

    int hPadding=getPaddingLeft()+getPaddingRight();
    int vPadding=getPaddingTop()+getPaddingBottom();

    previewWidth-=hPadding;
    previewHeight-=vPadding;

    if(previewWidth>previewHeight*mAspectRatio)
        previewWidth=(int) (previewHeight*mAspectRatio+.5);
    else
        previewHeight=(int)(previewWidth/mAspectRatio+.5);
    previewWidth+=hPadding;
    previewHeight+=vPadding;
    Log.d(TAG,"Aspect ratio "+mAspectRatio);
    Log.d(TAG, "Width: "+previewWidth+" Height: "+previewHeight);
    super.onMeasure(MeasureSpec.makeMeasureSpec(previewWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(previewHeight, MeasureSpec.EXACTLY));
}

protected void onSizeChanged(int w,int h,int oldw,int oldh)
{
    if(mListener!=null)
        mListener.onSizeChanged(w, h);
}
}

并设置预览和图片大小,如下所示:

  private Size getOptimalPreviewSize(List<Size> supportedSizeList,double targetRatio)
{
    final double ASPECT_TOLERANCE=0.05;
    double minDiff=Double.MAX_VALUE;
    Size optimalSize=null;
    Display display=getWindowManager().getDefaultDisplay();
    @SuppressWarnings("deprecation")
    int targetHeight=Math.min(display.getWidth(), display.getHeight());
    if(targetHeight<=0)
    {   
        WindowManager windowManager=(WindowManager)getSystemService(Context.WINDOW_SERVICE);
        targetHeight=windowManager.getDefaultDisplay().getHeight();
    }
    for(Size size:supportedSizeList)
    {
        double ratio=(double)size.width/size.height;
        if(Math.abs(targetRatio-ratio)>ASPECT_TOLERANCE)
            continue;
        if(Math.abs(size.height-targetHeight)<minDiff)
        {
            optimalSize=size;
            minDiff=Math.abs(size.height-targetHeight);
        }
    }

    for(Size size:supportedSizeList)
    {
        if((Math.abs(size.height-targetHeight))<minDiff)
        {   
            optimalSize=size;
            minDiff=Math.abs(size.height-targetHeight);
        }
    }
    return optimalSize;
}

private Size getDesiredPictureSize(List<Size> supportedSizeList)
{
    //Resolution is widthxheight

    Size result=null;
    final int minArea=500*500;  
    final int maxArea=1000*1000;
    for(Size size:supportedSizeList)
    {
        if(size.width*size.height>minArea && size.width*size.height<maxArea)
        {
            if(result==null)
                result=size;
            else
            {
                int resultArea=result.width*result.height;
                int sizeArea=size.width*size.height;
                if(resultArea<sizeArea)
                {   
                    result=size;
                }   
            }
        }
    }
    return result;
 }

我使用这里的代码将宽高比设置为图片大小:

    mParameters=mCamera.getParameters();
    List<Size> supportedPictureSizes=mParameters.getSupportedPictureSizes();
    List<Size> supportedPreviewSizes=mParameters.getSupportedPreviewSizes();
    mPictureSize=getDesiredPictureSize(supportedPictureSizes);
    double targetRatio=(double)mPictureSize.width/mPictureSize.height;
    mPreviewPanel=findViewById(R.id.frame_layout);
    mPreviewFrameLayout=(PreviewFrameLayout)findViewById(R.id.frame);
    mPreviewFrameLayout.setAspectRatio(targetRatio);

该布局的父级是RelativeLayout:

<com.example.newcameraproject.PreviewFrameLayout android:id="@+id/frame"
        android:layout_centerInParent="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <SurfaceView android:id="@+id/camera_preview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
      </com.example.newcameraproject.PreviewFrameLayout>

这包含在主相机布局中,如下所示:

  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
>

 <include layout="@layout/preview_frame"/>

 </LinearLayout>

EDIT:

纵向:

CameraActivity(6502): Resolution Width: 720 Resolution Height: 1184
CameraActivity(6502): The Picture Width: 1152 The Picture Height: 864
CameraActivity(6502): The Preview Width:960 Preview Height: 720
CameraActivity(6502): Picture Ratio: 1.3333333333333333
CameraActivity(6502): Preview Ratio: 1.3333333333333333
PreviewFrameLayout(6502): Left: 0 Right: 0 Top: 0 Bottom: 0
PreviewFrameLayout(6502): Aspect ratio 0.75
PreviewFrameLayout(6502): Width: 720 Height: 960

由于是纵向方向,所以纵横比是倒置的。

if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT)
        ratio=1/ratio;

相机显示为一个比活动稍小的框。

景观方向:

  CameraActivity(6502): Resolution Width: 1196 Resolution Height: 720
  CameraActivity(6502): The Picture Width: 1152 The Picture Height: 864
  CameraActivity(6502): The Preview Width:960 Preview Height: 720
  CameraActivity(6502): Picture Ratio: 1.3333333333333333
  CameraActivity(6502): Preview Ratio: 1.3333333333333333
  PreviewFrameLayout(6502): Left: 0 Right: 0 Top: 0 Bottom: 0
  PreviewFrameLayout(6502): Aspect ratio 1.3333333333333333
  PreviewFrameLayout(6502): Width: 787 Height: 590

 mPreviewSize=getOptimalPreviewSize(this,supportedPreviewSizes, targetRatio);
    Log.d(TAG, "The Preview Width:"+mPreviewSize.width+" Preview Height: "+mPreviewSize.height);
    double ratio=(double)mPreviewSize.width/mPreviewSize.height;
    Log.d(TAG,"Picture Ratio: "+targetRatio);
    Log.d(TAG, "Preview Ratio: "+ratio);
    int new_width=0, new_height=0;    
 if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT)
    {
        if((double)previewFrame.getWidth()/previewFrame.getHeight()<ratio)
        {
            new_width=(int)(Math.round(previewFrame.getHeight()*ratio));
            new_height=getWindowManager().getDefaultDisplay().getHeight();
        }
        else
        {
            new_width=getWindowManager().getDefaultDisplay().getHeight();
            new_height=(int)Math.round((double)new_width/ratio);
        }
    }
    if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE)
    {
        if((double)previewFrame.getWidth()/previewFrame.getHeight()<ratio)
        {
            new_width=(int)(Math.round(previewFrame.getHeight()*ratio));
            new_height=getWindowManager().getDefaultDisplay().getHeight();
        }
        else
        {
            new_width=getWindowManager().getDefaultDisplay().getWidth();
            new_height=(int)Math.round((double)new_width/ratio);
        }
    }

EDIT:

1.Ensured that getOptimalPreviewSize and other methods works,changed code outside of this post to do so.
2.Even though these methods now work,the preview was not filling the screen,so changed to FrameLayout.The final version(see above) now works for both landscape and portrait.
3.I have noticed that the image in the preview looks stretched when the Camera Activity is rotated to landscape.

添加了一个问题来解决这个问题使用 FrameLayout 时相机预览会拉伸 https://stackoverflow.com/questions/21255172/camera-preview-stretched-when-using-framelayout

EDIT2:

Camera PreviewFrameLayout 工作得几乎完美(它几乎是全屏)...当我将此代码添加到构造函数时,就在 ShutterButton 上方:

 public PreviewFrameLayout(Context c,AttributeSet attrs)
{
    super(c,attrs);
    setAspectRatio(4.0/3.0);
}

仍然存在一些问题,例如屏幕显示方向为 90 的横向拍照并预览......

我发现,尽管使用了ExifInterface and Matrix修复此轮换代码ImagePreviewActivity

Exif方向始终为0,我上次修复了这个问题(没有使用PreviewFrameLayoutParameters.setRotation设置方向时的代码...但它似乎在这里不起作用


我看不到哪里getOptimalPreviewSize()叫做;此外,没有真正的理由将预览尺寸设置为与屏幕相匹配;通常,制造商会选择默认的相机预览,以便在屏幕上看起来不错(这涉及缩放)。

有了这些,您发布的代码就可以大大简化。如果我理解正确,您在活动中固定了 screenOrientation,并且希望用相机预览填充所有屏幕,保留宽高比以匹配所需的图片大小。

这个简单的例子 https://stackoverflow.com/a/21189749/192373,显示如何设置预览表面视图的宽度和高度。如果这对您来说还不够,请随时询问更多详细信息。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

相机预览未全屏显示(显示在框中) 的相关文章

  • 无法读取第 0 行,第 -1 列

    我正在尝试复制使用 SQLite 管理器创建的数据库 我在其中执行了以下操作 CREATE TABLE android metadata locale TEXT DEFAULT en US and INSERT INTO android m
  • 在 Eclipse 中删除空块之前的新行

    我更喜欢奥尔曼式 http en wikipedia org wiki Brace style Allman style大括号 例如 if foo magical prancing unicorn stuff 而不是 if foo unma
  • 生成一定长度的所有排列

    假设我们有一个字母表 abcdefghiklimnop 如何以有效的方式以五个一组的形式重复该字母表来递归生成排列 几天来我一直在为此苦苦挣扎 任何反馈都会有帮助 本质上这与 生成给定字符串的所有排列 https stackoverflow
  • java彩色滚动条搜索结果

    我将如何在 Java 中自定义滚动条 以便我可以进行像 chrome 一样的搜索 也就是说在结果所在的位置放置彩色条纹 我不想要一个库 因为我更喜欢自己编写代码 另外 我不想失去我拥有的 L F 欢迎举例 实际上 它将查看一个大的文本文件或
  • 扩展多个类

    我知道 Java 不支持多重继承 因为不允许扩展多个类 我只是想知道我的问题是否有解决方法 我有一个名为CustomAction需要扩展两个抽象类 BaseAction and QuoteBaseAction 我无法更改这些抽象类中的任何一
  • 我怎样才能实现CoverFlow视图[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我想用点线布局实现溢出视图 目前我正在使用 polidea 封面流库 URL github https
  • 为休息服务实施 JUnit 测试

    我必须为我的休息服务实现一些 JUnit 测试 例如 这是我的休息服务之一 Path dni fe public class HelloWorld POST Path home Consumes MediaType APPLICATION
  • 如何获取 JDBC 中 UPDATE 查询影响的所有行?

    我有一项任务需要使用更新记录PreparedStatement 一旦记录被更新 我们知道更新查询返回计数 即受影响的行数 但是 我想要的不是计数 而是受更新查询影响的行作为响应 或者至少是受影响的行的 id 值列表 这是我的更新查询 UPD
  • BigDecimal汇总统计

    我有一个 BigDecimal 列表 List
  • 地理围栏不可用以及如何处理

    我正在 Android 上使用地理围栏 它在大多数手机上都工作正常 但在其中一些上 它不起作用 在我的错误日志中显示 地理围栏不可用 某些用户没有为 Google Play 服务启用位置跟踪 我认为这就是地理围栏在他们的手机上不起作用的原因
  • 布局聊天气泡问题:TextView 占满整个屏幕

    我正在研究泡泡聊天 我使用具有两种布局的适配器 一种用于传入消息 另一种用于我的消息 适配器工作正常 我的问题在于传入布局 无法很好地显示传入时间文本 当消息文本增长时 会填满屏幕的整个宽度 并隐藏消息时间的文本 第一个问题 如何才能实现这
  • 通知管理器所需的权限

    我正在尝试使用以下命令将振铃器设置为静音且请勿打扰优先级 AudioManager myAudioMgr AudioManager context getSystemService Context AUDIO SERVICE Notific
  • 在 Tensorflow-lite Android 中将位图转换为 ByteBuffer(浮点)

    在用于图像分类的tensorflow lite android演示代码中 图像首先转换为ByteBuffer格式以获得更好的性能 这种从位图到浮点格式的转换以及随后到字节缓冲区的转换似乎是一个昂贵的操作 循环 按位运算符 float mem
  • 谷歌地图URL中参数的含义是什么

    我正在 Android 上使用 Webkit 浏览器 我想在以下 URL 中获得一个红色 A 符号
  • Spring MVC:通用 DAO 和服务类

    我正在 Spring MVC 中编写网页 我使用 Generic DAO 编写了所有 DAO 现在我想重写我的服务类 我该如何写 通用服务 我的 DAO 如下 DAO package net example com dao import j
  • Android 模拟器提示和技巧 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • junit4 使用特定测试方法创建测试套件

    在 junit4 中 我想执行来自不同类的特定测试方法 即想要使用来自不同类的特定测试方法创建一个测试套件 假设我有两门课 public class Test Login Test public void test Login 001 Sy
  • 如何将 Android 应用程序添加到已在 iOS 应用程序中使用的现有 Firebase 项目?

    我一直在我的 iOS 应用程序中使用 Firebase 项目 我现在想开始为 Android 应用程序使用相同的 Firebase 项目及其所有数据库和存储 在您的应用程序下Overview菜单 你应该按添加另一个应用程序并选择Androi
  • 使用 Android O 的“android:fontFamily”时出现错误“文件名必须以 .xml 结尾”?

    Android O 引入了一项新功能 XML 中的字体 它允许您将字体用作资源 我正在创建font资源文件中的文件夹 由安卓开发者 https developer android com preview features working w
  • 调用外部应用程序

    如何从我的应用程序调用外部应用程序 例如 我需要打电话Shazam 应用程序 来自我的应用程序 我可以在应用程序的包名称中看到logcat 这对任何目的都有用吗 特别是对于 Shazam 以下代码有效 Intent intent new I

随机推荐