将图像视图定位为相机预览上的叠加图像

Posted

技术标签:

【中文标题】将图像视图定位为相机预览上的叠加图像【英文标题】:Position an Image View as Overlay Image on Camera Preview 【发布时间】:2016-11-13 13:27:54 【问题描述】:

您好,我正在使用 android 相机 API 编写相机应用程序!

它具有以下功能:

该应用在相机预览上具有图像视图 用户可以将该图像视图拖放到相机预览中 drop 事件捕获图像视图的放置位置 用户捕获图像,图像视图被添加到用户所需拖放位置的照片上

这是用于图像视图拖放的代码:

@Override
public boolean onTouch(View view, MotionEvent event) 
    final int X = (int) event.getRawX();
    final int Y = (int) event.getRawY();
    switch (event.getAction() & MotionEvent.ACTION_MASK) 
        case MotionEvent.ACTION_DOWN:
            RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
            _xDelta = X - lParams.leftMargin;
            _yDelta = Y - lParams.topMargin;
            break;
        case MotionEvent.ACTION_UP:
            xloc=X;
            yloc=Y;
            Toast.makeText(getContext(), "Location==="+Integer.toString(xloc)+"==="+Integer.toString(yloc), Toast.LENGTH_SHORT).show();
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            break;
        case MotionEvent.ACTION_POINTER_UP:
            break;
        case MotionEvent.ACTION_MOVE:
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
                    .getLayoutParams();
            layoutParams.leftMargin = X - _xDelta;
            layoutParams.topMargin = Y - _yDelta;
            layoutParams.rightMargin = -250;
            layoutParams.bottomMargin = -250;
            view.setLayoutParams(layoutParams);
            break;
    
    mRrootLayout.invalidate();
    return true;

xloc 和 yloc 包含用户将删除该图像视图的位置!


这是我用来确定设备方向的代码。这是由传感器完成的,因为活动在 manifest.xml 中默认设置为纵向

        @Override
        public void onSensorChanged(SensorEvent event) 
            float x = event.values[0];
            float y = event.values[1];

            if (x < 5 && x > -5 && y > 5)
                //portrait UP ↑↑↑
                cam_orientation = 0;
                image_watermark.setRotation(0); //rotating the water mark with screen orientation
            
            else if (x<-5 && y<5 && y>-5) 
                //landscape RIGHT →→→
                cam_orientation = 3;
                image_watermark.setRotation(270);
            
            else if (x<5 && x>-5 && y<-5) 
                //Portrait DOWN ↓↓↓
                cam_orientation = 4;
                image_watermark.setRotation(0);
            
            else if (x>5 && y<5 && y>-5)
                //Landscape LEFT ←←←
                cam_orientation = 1;
                image_watermark.setRotation(90);
            

        

这是捕获图像的代码

   private Camera.PictureCallback mPicture = new Camera.PictureCallback() 

    @Override
    public void onPictureTaken(byte[] data, Camera camera) 

        File pictureFile = getOutputMediaFile(1);
        if (pictureFile == null)
            Log.i("#LOGTAG pic","Exception");
            return;
        

        try 
            //rotate the image view as expected
            BitmapFactory.Options options = new BitmapFactory.Options();
            Bitmap mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);


            if(cam_orientation==0)
                //portrait UP ↑↑↑
                if(cam_id==1)
                    //this is front camera id=1
                    mBitmap= rotate(mBitmap, 270);
                    mBitmap=flip(mBitmap);
                
                if(cam_id==0)
                    mBitmap= rotate(mBitmap, 90);
                
            

            if(cam_orientation==1)
                //Landscape LEFT ←←←
                if(cam_id==1)
                    //this is front camera id=1
                    mBitmap= rotate(mBitmap, 0);
                    mBitmap=flip(mBitmap);
                
                if(cam_id==0)
                    //this is back camera id=0
                    mBitmap= rotate(mBitmap, 0);
                
            

            if(cam_orientation==3)
                //landscape RIGHT →→→
                if(cam_id==1)
                    //this is front camera id=1
                    mBitmap= rotate(mBitmap, 180);
                    mBitmap=flip(mBitmap);
                
                if(cam_id==0)
                    //this is back camera id=0
                    mBitmap= rotate(mBitmap, 180);
                
            

            if(cam_orientation==4)
                //Portrait DOWN ↓↓↓
                if(cam_id==1)
                    //this is front camera id=1
                    mBitmap= rotate(mBitmap, 90);
                    mBitmap=flip(mBitmap);
                
                if(cam_id==0)
                    //this is back camera id=0
                    mBitmap= rotate(mBitmap, 270);
                
            

            //add the water mark to the camera photo bitmap here
            Bitmap mutableBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, true);

            image_watermark.buildDrawingCache();
            Bitmap bmap = image_watermark.getDrawingCache();

            Bitmap final_image=Bitmap.createScaledBitmap(bmap,(image_watermark.getMeasuredWidth())*2,(image_watermark.getMeasuredWidth())*2,false);
            Canvas canvas = new Canvas(mutableBitmap);

            if(cam_id==1)
                canvas.drawBitmap(icon,(int)(xloc*1.5),(int)(yloc*1.5), null); //setting the location of the water mark image view on front camera/photo
            

            if(cam_id==0)
                canvas.drawBitmap(icon,xloc*2,yloc*2, null);
                 //setting the location of the water mark image view on back camera/photo
            

            FileOutputStream fos = new FileOutputStream(pictureFile);
            mutableBitmap.compress(Bitmap.CompressFormat.JPEG,100,fos);

            fos.close();


我在相机拍摄的照片上设置水印图像视图的位置时遇到问题!我只想将水印图像视图的位置设置为用户拖放该水印图像视图的位置。

虽然代码运行良好,但在为不同设备设置拍摄照片上的水印图像视图位置时缺乏精确度和准确性。

我一直在尝试不同的设备,但每个设备都会扭曲准确的位置。

谁能给我任何想法或更好的方法来在相机拍摄的照片上添加水印图像!

请注意相机的 ID 为:

   cam_id=1 for the from camera
   cam_id=0 for the back camera

我需要一种方法,以便能够在所有设备方向模式以及至少在某些多个设备上定位我的水印图像。

谢谢

假设当屏幕处于纵向位置时,如果我在此蓝色按钮上拖动图像视图,则图像应保存在与蓝色按钮相同位置的相机拍摄照片上!

同样,如果我将它放在那个盒子上,相机拍摄的照片应该在横向模式下将这个图像视图定位在那个盒子上!

下面是使用的 XML

     <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
tools:context="">

<LinearLayout
    android:layout_
    android:layout_
    android:orientation="vertical">

    <LinearLayout
        android:layout_
        android:layout_
        android:orientation="horizontal"
        android:background="@color/colorAccent">
        <ToggleButton
            android:id="@+id/flipper"
            android:layout_
            android:layout_
            android:text=""
            android:background="@drawable/my_btn_toggle"
            android:textOff=""
            android:textOn=""/>
    </LinearLayout>

    <RelativeLayout
        android:layout_
        android:layout_
        android:layout_weight="10"
        android:id="@+id/root">

        <FrameLayout
            android:layout_
            android:layout_
            android:id="@+id/camera_preview">


        </FrameLayout>

        <ImageView
            android:layout_
            android:layout_
            android:id="@+id/watermark"
            />

    </RelativeLayout>

<LinearLayout
  android:layout_
  android:layout_
  android:layout_weight="1"
  android:background="#000"
  android:layout_alignParentBottom="true"
  android:gravity="center"
  android:id="@+id/capture_layout">
    <Button
        android:layout_
        android:layout_
        android:id="@+id/capture"
        android:text="Capture"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"/>

   <Button
    android:layout_
    android:layout_
    android:id="@+id/neg"
    android:text="Cancel Para"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"/>

 </LinearLayout>
  </LinearLayout>
</RelativeLayout>

【问题讨论】:

【参考方案1】:

您可以将包含相机视图和水印的视图转换为位图并将其保存到手机内存中,而无需直接从相机捕获图像。它将像屏幕截图一样工作。您的水印将放置在其出现的同一位置。

确保相机视图和水印图像视图都在同一个父视图中,并将它们的父视图转换为位图。

这个Link 可以帮助你。

【讨论】:

我刚刚尝试过这个技巧,问题仍然存在 请分享您的 XML。【参考方案2】:

试试看:

扩展您的 SurfaceView 并覆盖 onDraw() 方法。 在那里,您可以在预览中插入您的图像。你可以 之后将其添加到 Jpeqcall 中

【讨论】:

给我看一个例子【参考方案3】:

只需用这个替换你的Camera.PictureCallback

private Camera.PictureCallback mPicture = new Camera.PictureCallback() 

    @Override
    public void onPictureTaken(byte[] data, Camera camera) 
        File pictureFile = getOutputMediaFile(1);
        if (pictureFile == null)
            Log.i("#LOGTAG pic","Exception");
            return;
        

        //rotate the image view as expected
        Bitmap mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);

        if(cam_orientation==0)
            //portrait UP ↑↑↑
            if(cam_id==1)
                //this is front camera id=1
                mBitmap= rotate(mBitmap, 270);
                mBitmap=flip(mBitmap);
            
            if(cam_id==0)
                mBitmap= rotate(mBitmap, 90);
            
        

        if(cam_orientation==1)
            //Landscape LEFT ←←←
            if(cam_id==1)
                //this is front camera id=1
                mBitmap= rotate(mBitmap, 0);
                mBitmap=flip(mBitmap);
            
            if(cam_id==0)
                //this is back camera id=0
                mBitmap= rotate(mBitmap, 0);
            
        

        if(cam_orientation==3)
            //landscape RIGHT →→→
            if(cam_id==1)
                //this is front camera id=1
                mBitmap= rotate(mBitmap, 180);
                mBitmap=flip(mBitmap);
            
            if(cam_id==0)
                //this is back camera id=0
                mBitmap= rotate(mBitmap, 180);
            
        

        if(cam_orientation==4)
            //Portrait DOWN ↓↓↓
            if(cam_id==1)
                //this is front camera id=1
                mBitmap= rotate(mBitmap, 90);
                mBitmap=flip(mBitmap);
            
            if(cam_id==0)
                //this is back camera id=0
                mBitmap= rotate(mBitmap, 270);
            
        

        Bitmap newImage = Bitmap.createBitmap(
            mBitmap.getWidth(), 
            mBitmap.getHeight(), 
            Bitmap.Config.ARGB_8888
        );

        Canvas canvas = new Canvas(newImage);
        canvas.drawBitmap(mBitmap, 0f, 0f, null);

        image_watermark.buildDrawingCache();
        Drawable drawable = new BitmapDrawable(getResources(), image_watermark.getDrawingCache());
        drawable.setBounds(
            xloc, 
            yloc, 
            image_watermark.getMeasuredWidth() + xloc, 
            image_watermark.getMeasuredHeight() + yloc
        );
        drawable.draw(canvas);

        try
        
            FileOutputStream out = new FileOutputStream(pictureFile);
            newImage.compress(Bitmap.CompressFormat.JPEG, 100, out);

            out.flush();
            out.close();
        
        catch (Exception e) 
            Log.d("In Saving File", e.getMessage(), e);
        

        Log.d("Image", "Pic taken!");

        // Camera preview should be started again after taking a picture
        camera.startPreview();

        // Release image
        newImage.recycle();
        newImage = null;
    

这应该可以解决您的问题。

【讨论】:

该方法只是挂机,不保存图片! 有什么例外吗?它挂在哪一行? 没有例外,但我不知道它挂在哪里 它只是锁定了这个方法,从不保存拍摄的照片 你能进入代码看看它挂在哪里吗?【参考方案4】:

你可以使用这个library,这是一个简单的Android水印库,将XML(VIEW)转换为位图

private Bitmap generateWaterMark(Bitmap src) 

    //src is your original image, like camera preview
    WaterMark waterMark = new WaterMark(this);
    View view = getLayoutInflater().inflate(R.layout.register_email_layout, null, false);

    //Manipulate your view like you prefer, then invoke the method getImageWaterMarkFromView

    return waterMark.getImageWaterMarkFromView(src, view);

【讨论】:

以上是关于将图像视图定位为相机预览上的叠加图像的主要内容,如果未能解决你的问题,请参考以下文章

Android中的相机,如何获得最佳尺寸,预览尺寸,图片尺寸,视图尺寸,图像失真

iPhone相机,如何避免相机在预览视图上叠加;如何知道何时进入预览视图?

Android上的相机预览处理

ImageView 在相机表面视图后面移动

裁剪/剪辑相机预览以仅显示图像的上半部分

自定义相机视图预览层加上大小的手机问题