【问题标题】:Android: Overlay on Android Camera PreviewAndroid:Android 相机预览上的叠加层
【发布时间】:2011-09-19 04:06:23
【问题描述】:

我正在使用相机 API 并调用相机。

我想在相机预览的顶部显示一个标题(用于品牌宣传)。标题是 jpeg 图像。

有可能吗?任何帮助表示赞赏。

提前致谢。

我的代码如下。

public class CameraActivity extends Activity {
    @Override
    protected void onPause() {

        super.onPause();
    }

    private static final int CAMERA_PIC_REQUEST = 2500;
    private Bitmap image2;
    private Bitmap bm;
    public static String imagepath;
    public static int x=1;
    private RdmsDbAdapter dbHelper;
    @Override



    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.header);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        //caling new incident
        if(IncidentFormActivity.incident_id == null || IncidentFormActivity.isDisable==true){
            //DBAdapter instance created and connection opened. 
            dbHelper = new RdmsDbAdapter(CameraActivity.this);
            dbHelper.open();

            //setting up flags
            NewIncidentHelper nih = new NewIncidentHelper();
            nih.setUpNewIncident();

            //setting up incident_id
            String Date= IncidentIdGenerator.getDate();
            String Time = IncidentIdGenerator.getTime();

            IncidentFormActivity.incident_id = IncidentIdGenerator.now("ddMMyyyyHHmmss");
            dbHelper.executeSQL("insert into incident values ('" + IncidentFormActivity.incident_id
                    + "', ' ', ' ', ' ', ' ', '"+Date+"', '0','0','0','0','0','0','0','0','0','"+Time+"')");
            dbHelper.close();
        }

        //calling camera
        Intent cameraIntent = new Intent(
                android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);


    }
    public String getPath(Uri uri) {
        String[] projection = { MediaStore.Images.Media.DATA };
        Cursor cursor = managedQuery(uri, projection, null, null, null);
        int column_index = cursor
                .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    }

    //back key on phone pressed
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
        case KeyEvent.KEYCODE_BACK:
            Intent i= new Intent(CameraActivity.this, IncidentFormActivity.class);
            startActivity(i);
            this.finish();

            break;

        default:
            break;
        }
        return super.onKeyDown(keyCode, event);
    }

    //handle response came from camera when the picture is taken.
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == CAMERA_PIC_REQUEST && resultCode == RESULT_OK) {
                final ImageView img = new ImageView(this);
                img.setLayoutParams(new LayoutParams(100, 100));
                image2 = (Bitmap) data.getExtras().get("data");
                img.setImageBitmap(image2);
                String incident_ID = IncidentFormActivity.incident_id;
                //l2.addView(img);
                    imagepath="/sdcard/RDMS/"+incident_ID+ x + ".png";
                File file = new File(imagepath);
                try {
                     bm = Bitmap.createScaledBitmap( image2,400, 300, true);
                    file.createNewFile();
                    FileOutputStream ostream = new FileOutputStream(file);
                    bm.compress(CompressFormat.PNG, 90, ostream);
                    ostream.close(); 
                    //Initialising db class and inserting values
                    dbHelper = new RdmsDbAdapter(CameraActivity.this);
                    dbHelper.open();
                    dbHelper.executeSQL("insert into files values ('"+imagepath+"', '"+IncidentFormActivity.incident_id+"')");
                    dbHelper.close();

                } catch (Exception e) {
                    e.printStackTrace();
                    Toast.makeText(getApplicationContext(),"yourfirst  error message is "
                                            + e.toString(), 1000).show();
                }
                x++;
                final AlertDialog.Builder alert = new AlertDialog.Builder(
                        CameraActivity.this);

                alert.setTitle(getString(R.string.anotherimage));
                alert.setCancelable(false);
                //alert.setMessage("Play or Delete the Video selected");
                //alert.setIcon(R.drawable.vid_red);
                alert.setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        Intent sendingpage = new Intent(CameraActivity.this, CameraActivity.class);
                          startActivity(sendingpage);

                    }
                });
                alert.setNegativeButton(getString(R.string.no),
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                Intent callback = new Intent (CameraActivity.this, IncidentFormActivity.class);
                                startActivity(callback);
                            }
                        });

                alert.show();


            }
            if(resultCode==RESULT_CANCELED)
            {

                AlertDialog.Builder builder = new AlertDialog.Builder(CameraActivity.this);

                builder.setMessage(getString(R.string.areuexit)).setCancelable(
                        false).setPositiveButton(getString(R.string.yes),
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                Intent i= new Intent(CameraActivity.this, IncidentFormActivity.class);
                                startActivity(i);
                                CameraActivity.this.finish();
                            }
                        }).setNegativeButton(getString(R.string.no),
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.cancel();
                                Intent i= new Intent(CameraActivity.this, CameraActivity.class);                            startActivity(i);
                                CameraActivity.this.finish();
                            }
                        });

                builder.show();



            }
        }
    }

【问题讨论】:

  • 通过标题,您是指相机应用顶部的图形还是某种类似水印的图形?
  • 是的,我想在顶部显示一个图形作为标题。谢谢。
  • 是的,我想在顶部显示一个图形作为相机预览顶部的标题。没什么,我什至不想改变拍摄的图像。谢谢。
  • 很好的关注点分离

标签: android header camera


【解决方案1】:

您可以使用 SurfaceView 并创建一个将打开相机的 CustomView,您可以相应地在 xml 中调整其大小。下面是一个伪代码。

创建一个扩展 SurfaceView 的类并在其中打开相机

CapturePreview.java

public class CapturePreview extends SurfaceView implements SurfaceHolder.Callback{

    public static Bitmap mBitmap;
    SurfaceHolder holder;
    static Camera mCamera;

    public CapturePreview(Context context, AttributeSet attrs) {
        super(context, attrs);

        holder = getHolder();
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {

        Camera.Parameters parameters = mCamera.getParameters();
        parameters.getSupportedPreviewSizes();
        mCamera.setParameters(parameters);
        mCamera.startPreview();
    }
    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        try {
            mCamera = Camera.open();
            mCamera.setPreviewDisplay(holder);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mCamera.stopPreview();
        mCamera.release();
    }
    /***
     * 
     *  Take a picture and and convert it from bytes[] to Bitmap.
     *  
     */
    public static void takeAPicture(){  

        Camera.PictureCallback mPictureCallback = new PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {

                BitmapFactory.Options options = new BitmapFactory.Options();
                mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
            }
        };
        mCamera.takePicture(null, null, mPictureCallback);
    }
}

现在您必须像这样在 xml 中包含使用 SurfaceView 创建的视图

ma​​in.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">

  <FrameLayout 
  android:id="@+id/mySurfaceView"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">

  <com.cam.CapturePreview 
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">
  </com.cam.CapturePreview>

  </FrameLayout>

  <LinearLayout 
  android:layout_below="@id/mySurfaceView" 
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:layout_centerInParent="true"
  android:gravity="center">

  <ImageView android:id="@+id/myImageView" 
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:src="@drawable/icon"/>
  </LinearLayout>  

</RelativeLayout>

现在您可以在任何Acitivty 中使用此 main.xml,这将打开带有ImageView 的相机。 谢谢....

【讨论】:

  • 必须删除 android:layout_below="@id/mySurfaceView" 才能使代码正常工作。
  • 相机预览很失真
  • 那现在有什么解决办法?
  • 查看我从 Google 的 Camera2Video 派生的示例代码,其中包含折旧问题的解决方案。 github.com/chriscborg/android-Camera2Video
【解决方案2】:

您必须自己处理整个相机预览和拍照。查看samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview 的示例。您可以在预览区域上拥有自己的布局并将图形添加到其中。

示例链接

https://developer.android.com/training/camera/cameradirect#java

【讨论】:

【解决方案3】:

您可以在 FrameLayout 的帮助下这样做:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" >

  <android.view.SurfaceView
  android:id="@+id/surface"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" />

<ImageView
    android:id = "@+id/header"
    android:layout_width = "wrap_content"
    android:layout_height = "wrap_content" />

</FrameLayout>

这个camera project 会帮助你。

【讨论】:

    【解决方案4】:

    恐怕您必须自己实现相机预览屏幕。理论上,可以通过修改布局或创建覆盖窗口将覆盖添加到其他应用程序。第一种方法是不可能实现的,第二种方法我认为可以实现,但这是一种黑客和容易出错的方法。

    实现您自己的相机活动并不是一项非常困难的任务,但它相当具有挑战性。我建议您查看默认的相机应用程序。这是它的源代码:https://github.com/android/platform_packages_apps_camera

    【讨论】:

    • “不是一项非常困难的任务,但它是相当具有挑战性的”嗯,它是哪一个?
    【解决方案5】:

    看看你的 XML 应该是这样的:

     <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent" >
    
    <android.view.SurfaceView
     android:id="@+id/surface"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent" />
    
    <ImageView
    android:id = "@+id/header"
    android:layout_width = "wrap_content"
    android:layout_height = "wrap_content" />
    
    </FrameLayout>
    

    对于 java 代码,您应该在活动中扩展 SurfaceHolder.Callback,然后像这样将相机附加到表面视图,我的完整代码请注意位图和画布,这是棘手的部分:

     public class MainActivity extends Activity implements SurfaceHolder.Callback 
    {
      private Camera camera = null;
      private SurfaceView cameraSurfaceView = null;
      private SurfaceHolder cameraSurfaceHolder = null;
      private boolean previewing = false;
      RelativeLayout relativeLayout;
    
    
    
    
    
      private Button btnCapture = null;
      private Button btnsave = null;
      private Button btnshare = null;
      private boolean isSaved=false;
      private boolean isCaptured=false;
    
      @Override
      protected void onCreate(Bundle savedInstanceState) 
      {
        super.onCreate(savedInstanceState);
    
        getWindow().setFormat(PixelFormat.TRANSLUCENT);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(
                             WindowManager.LayoutParams.FLAG_FULLSCREEN,
                             WindowManager.LayoutParams.FLAG_FULLSCREEN);
    
        setContentView(R.layout.activity_main);
    
        relativeLayout=(RelativeLayout) findViewById(R.id.containerImg);
        relativeLayout.setDrawingCacheEnabled(true);
        cameraSurfaceView = (SurfaceView)
                                           findViewById(R.id.surfaceView1);
      //  cameraSurfaceView.setLayoutParams(new FrameLayout.LayoutParams(640, 480));
        cameraSurfaceHolder = cameraSurfaceView.getHolder();
        cameraSurfaceHolder.addCallback(this);
    //    cameraSurfaceHolder.setType(SurfaceHolder.
      //                                               SURFACE_TYPE_PUSH_BUFFERS);
    
    
    
    
        btnCapture = (Button)findViewById(R.id.capturebtn);
        btnCapture.setOnClickListener(new OnClickListener() 
        {   
          @Override
          public void onClick(View v) 
          {
             camera.takePicture(cameraShutterCallback, 
                                           cameraPictureCallbackRaw,
                                           cameraPictureCallbackJpeg);
             isCaptured=true;
          }
        });
        btnsave = (Button)findViewById(R.id.savebtn);
        btnsave.setOnClickListener(new OnClickListener() {
    
            @Override
            public void onClick(View v) {
                 FrameLayout frm = (FrameLayout)findViewById(R.id.frameLayout1);
                    frm.setDrawingCacheEnabled(true);
                    frm.buildDrawingCache();
                    Bitmap bitmap = frm.getDrawingCache();
                    try {
                        File rootFile=new File(Environment.getExternalStorageDirectory().toString()+"/MYCAMERAOVERLAY");
                        rootFile.mkdirs();
                        Random generator = new Random();
                        int n = 10000;
                        n = generator.nextInt(n);
                        String fname = "Image-"+ n +".png";
    
                        File resultingfile = new File(rootFile, fname);
    
                        if (resultingfile.exists ()) resultingfile.delete (); 
                        try {
                               FileOutputStream Fout = new FileOutputStream(resultingfile);
                               bitmap.compress(CompressFormat.PNG, 100, Fout);
                               Fout.flush();
                               Fout.close();
    
                        } catch (FileNotFoundException e) {
                            Log.d("In Saving File", e + "");
                    }
                    } catch(IOException e){
                        Log.d("In Saving File", e + "");
                    }
                    isSaved=true;
                }
            });
        btnshare = (Button)findViewById(R.id.sharebtn);
        btnshare.setOnClickListener(new OnClickListener() {
    
            @Override
            public void onClick(View v) {
                if((isSaved)&&(isCaptured)){
                    // TODO sharing what ever we saved 
                    // take the path
    
    
                }
    
            }
        });
       } 
    
    
      ShutterCallback cameraShutterCallback = new ShutterCallback() 
      {  
        @Override
        public void onShutter() 
        {
          // TODO Auto-generated method stub   
        }
      };
    
      PictureCallback cameraPictureCallbackRaw = new PictureCallback() 
      {  
        @Override
        public void onPictureTaken(byte[] data, Camera camera) 
        {
          // TODO Auto-generated method stub   
        }
      };
    
      PictureCallback cameraPictureCallbackJpeg = new PictureCallback() 
      {  
        @Override
        public void onPictureTaken(byte[] data, Camera camera) 
        {
          // TODO Auto-generated method stub   
          Bitmap cameraBitmap = BitmapFactory.decodeByteArray
                                                                      (data, 0, data.length);
    
       int   wid = cameraBitmap.getWidth();
         int  hgt = cameraBitmap.getHeight();
    
        //  Toast.makeText(getApplicationContext(), wid+""+hgt, Toast.LENGTH_SHORT).show();
          Bitmap newImage = Bitmap.createBitmap
                                            (wid, hgt, Bitmap.Config.ARGB_8888);
    
          Canvas canvas = new Canvas(newImage);
    
          canvas.drawBitmap(cameraBitmap, 0f, 0f, null);
    
          camera.startPreview();
    
          newImage.recycle();
          newImage = null;
    
          Intent intent = new Intent();
          intent.setAction(Intent.ACTION_VIEW);
    
          startActivity(intent);
    
        }
      };
    
      @Override
      public void surfaceChanged(SurfaceHolder holder, 
                                           int format, int width, int height) 
      {
        // TODO Auto-generated method stub
    
        if(previewing)
        {
          camera.stopPreview();
          previewing = false;
        }
        try 
        {
          Camera.Parameters parameters = camera.getParameters();
          parameters.setPreviewSize(640, 480);
          parameters.setPictureSize(640, 480);
          if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
              camera.setDisplayOrientation(-90);
    
          }
    
         // parameters.setRotation(90);
          camera.setParameters(parameters);
    
          camera.setPreviewDisplay(cameraSurfaceHolder);
          camera.startPreview();
          previewing = true;
        } 
        catch (IOException e) 
        {
          // TODO Auto-generated catch block
          e.printStackTrace();  
        }
      }
    
      @Override
      public void surfaceCreated(SurfaceHolder holder) 
      {
        // TODO Auto-generated method stub
        try
        {
          camera = Camera.open();
        }
        catch(RuntimeException e)
        {
          Toast.makeText(getApplicationContext(), "Device camera  is not working properly, please try after sometime.", Toast.LENGTH_LONG).show();
        }
      }
    
      @Override
      public void surfaceDestroyed(SurfaceHolder holder) 
      {
        // TODO Auto-generated method stub
          try{
    
    
        camera.stopPreview();
        camera.release();
        camera = null;
        previewing = false;
          }catch(Exception e){
              e.printStackTrace();
          }
      }
    

    }

    我想现在我也应该给你完整的 XML 部分。所以这里是:

      <?xml version="1.0" encoding="utf-8"?>
     <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:android1="http://schemas.android.com/apk/res/android"
    android:id="@+id/containerImg"
    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    android1:layout_gravity="bottom"
    android:orientation="vertical"
    android1:gravity="bottom" >
    
        <FrameLayout
        android:id="@+id/frameLayout1"
        android1:layout_width="wrap_content"
        android1:layout_height="wrap_content"
        android:gravity="center|top"
         >
    
     <SurfaceView
         android1:id="@+id/surfaceView1"
         android1:layout_width="100dip"
         android1:layout_height="150dip"
         android1:layout_gravity="center_horizontal" />
    
    <ImageView
    android1:id="@+id/imageView1"
    android1:layout_width="fill_parent"
    android1:layout_height="fill_parent"
    android:contentDescription="@string/app_dress_desc"
    android:gravity="center|bottom"
    android1:scaleType="center"
    android1:src="@drawable/dress" />
    
    </FrameLayout>
    
    
    <GridLayout
        android1:id="@+id/gridLayout1"
        android1:layout_width="match_parent"
        android1:layout_height="wrap_content"
        android1:layout_alignParentBottom="true"
        android1:layout_alignParentLeft="true"
        android1:columnCount="1"
        android1:gravity="center|bottom"
        android1:orientation="vertical" >
    
        <ImageButton
            android1:id="@+id/capturebtn"
            android1:layout_width="60dp"
            android1:layout_height="wrap_content"
            android1:layout_gravity="left"
            android1:src="@drawable/camera"
            android:contentDescription="@string/app_icon_camera_desc" />
    
        <ImageButton
            android1:id="@+id/savebtn"
            android1:layout_width="60dp"
            android1:layout_height="wrap_content"
            android1:layout_column="0"
            android1:layout_gravity="center_horizontal|top"
            android1:layout_row="0"
            android1:src="@drawable/save"
            android:contentDescription="@string/app_icon_save_desc" />
    
        <ImageButton
            android1:id="@+id/sharebtn"
            android1:layout_width="60dp"
            android1:layout_height="wrap_content"
            android1:layout_column="0"
            android1:layout_gravity="right|top"
            android1:layout_row="0"
            android1:src="@drawable/share"
            android:contentDescription="@string/app_icon_share_desc" />
    </GridLayout>
    

    共享按钮此时不起作用,但它会在单击捕获时保存整个帧布局。 希望它会有所帮助。

    【讨论】:

      【解决方案6】:

      另一种解决方法是用另一个包含标题图像的 XML 文件覆盖 Activity XML 文件。这样做:

      1. 在布局文件夹中创建一个新的布局文件。例如: overlay.xml
      2. 在其中插入一个ImageView,类似于:

        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto">
        
        <ImageView
            android:id="@+id/imageView1"
            android:layout_centerInParent="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/android" />
        
        
        </RelativeLayout>
        
      3. 然后在Activity java文件里面,即MotionDetector.java文件, 创建一个新方法addView()

           private void addView()
           {
               controlInflater = LayoutInflater.from(getBaseContext());
               View viewControl = controlInflater.inflate(R.layout.overlay, null);
               LayoutParams layoutParamsControl = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
               this.addContentView(viewControl, layoutParamsControl);
        
           }
        
      4. 最后从onCreate()调用addView()方法添加图片:

        protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.header);
        addView();
        

      那么最终结果将是SurfaceView 上方的图像叠加层。根据标题图像的质量,标题的渲染质量应该看起来是原始的。希望对您有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-19
        • 2012-10-06
        • 1970-01-01
        • 1970-01-01
        • 2014-10-11
        • 1970-01-01
        相关资源
        最近更新 更多