android 自定义动画3_android.graphics.Camera解读

时间:2023-02-09 15:38:03

android.graphics.Camera实现图像的旋转、缩放,配合Matrix实现图像的倾斜 by sodino

android.graphics.Camera可以对图像执行一些比较复杂的操作,诸如旋转与绽放,与Matrix可实现图像的倾斜。

个人总结Camera与Matrix的一些区别如下:

  1. Camera的rotate()相关方法是指定某一维度上旋转指定的角度。
  2. Matrix的rotate()相关方法实现的效果是顺时针旋转指定的角度;与Camera指定Z轴旋转效果相同,但方向相反。
  3. Camera的translate()方法根据某一维度上视点的位移实现图像的缩放,与Matrix的scale()相关方法作用效果相似,只是Matrix的scale()相关方法是直接指定缩放比例。
  4. Camera不支持倾斜操作,Matrix可以直接实现倾斜操作。

本文为练习Camera的使用。实现效果图如下:

android 自定义动画3_android.graphics.Camera解读

 

Camera的处理结果只是生成一个Matrix,该Matrix用于Bitmap或Canvas绘制Bitmap时才能产生旋转或缩放的效果。

代码如下:

  1. package lab.sodino.camera;
  2.  
  3. import android.app.Activity;
  4. import android.graphics.Bitmap;
  5. import android.graphics.Camera;
  6. import android.graphics.Matrix;
  7. import android.graphics.drawable.BitmapDrawable;
  8. import android.os.Bundle;
  9. import android.util.Log;
  10. import android.widget.ImageView;
  11. import android.widget.SeekBar;
  12. import android.widget.SeekBar.OnSeekBarChangeListener;
  13. import android.widget.TextView;
  14.  
  15. /**
  16.  * Camera与Matrix的比较:<br/>
  17.  * Camera的rotate()相关方法是指定某一维度上旋转指定的角度。<br/>
  18.  * Matrix的rotate()相关方法实现的效果是顺时针旋转指定的角度;与Camera指定Z轴旋转效果相同,但方向相反。<br/>
  19.  * 
  20.  * Camera的translate()方法根据某一维度上视点的位移实现图像的缩放,与Matrix的scale()相关方法作用效果相似,
  21.  * 只是Matrix的scale()相关方法是直接指定缩放比例。<br/>
  22.  * 
  23.  * Camera不支持倾斜操作,Matrix可以直接实现倾斜操作。<br/>
  24.  * 
  25.  * @author Sodino E-mail:sodinoopen@hotmail.com
  26.  * @version Time:2011-9-26 下午04:17:49
  27.  */
  28. public class ActCamera extends Activity implements OnSeekBarChangeListener {
  29.     private Camera camera;
  30.     // views
  31.     private SeekBar seekbarXRotate;
  32.     private SeekBar seekbarYRotate;
  33.     private SeekBar seekbarZRotate;
  34.     private TextView txtXRotate;
  35.     private TextView txtYRotate;
  36.     private TextView txtZRotate;
  37.     private SeekBar seekbarXSkew;
  38.     private SeekBar seekbarYSkew;
  39.     private SeekBar seekbarZTranslate;
  40.     private TextView txtXTranslate;
  41.     private TextView txtYTranslate;
  42.     private TextView txtZTranslate;
  43.     private ImageView imgResult;
  44.     // integer params
  45.     private int rotateX, rotateY, rotateZ;
  46.     private float skewX, skewY;
  47.     private int translateZ;
  48.  
  49.     /** Called when the activity is first created. */
  50.     @Override
  51.     public void onCreate(Bundle savedInstanceState) {
  52.         super.onCreate(savedInstanceState);
  53.         setContentView(R.layout.main);
  54.         // camera
  55.         camera = new Camera();
  56.         // initViews
  57.         // rotate
  58.         seekbarXRotate = (SeekBar) findViewById(R.id.seekbarXRotate);
  59.         seekbarXRotate.setOnSeekBarChangeListener(this);
  60.         seekbarYRotate = (SeekBar) findViewById(R.id.seekbarYRotate);
  61.         seekbarYRotate.setOnSeekBarChangeListener(this);
  62.         seekbarZRotate = (SeekBar) findViewById(R.id.seekbarZRotate);
  63.         seekbarZRotate.setOnSeekBarChangeListener(this);
  64.         txtXRotate = (TextView) findViewById(R.id.txtXRotate);
  65.         txtYRotate = (TextView) findViewById(R.id.txtYRotate);
  66.         txtZRotate = (TextView) findViewById(R.id.txtZRotate);
  67.         // translate
  68.         seekbarXSkew = (SeekBar) findViewById(R.id.seekbarXSkew);
  69.         seekbarXSkew.setOnSeekBarChangeListener(this);
  70.         seekbarYSkew = (SeekBar) findViewById(R.id.seekbarYSkew);
  71.         seekbarYSkew.setOnSeekBarChangeListener(this);
  72.         seekbarZTranslate = (SeekBar) findViewById(R.id.seekbarZTranslate);
  73.         seekbarZTranslate.setOnSeekBarChangeListener(this);
  74.         txtXTranslate = (TextView) findViewById(R.id.txtXSkew);
  75.         txtYTranslate = (TextView) findViewById(R.id.txtYSkew);
  76.         txtZTranslate = (TextView) findViewById(R.id.txtZTranslate);
  77.         imgResult = (ImageView) findViewById(R.id.imgResult);
  78.         // refresh
  79.         refreshImage();
  80.     }
  81.  
  82.     private void refreshImage() {
  83.         // 获取待处理的图像
  84.         BitmapDrawable tmpBitDra = (BitmapDrawable) getResources().getDrawable(R.drawable.honeycomb);
  85.         Bitmap tmpBit = tmpBitDra.getBitmap();
  86.         // 开始处理图像
  87.         // 1.获取处理矩阵
  88.         // 记录一下初始状态。save()和restore()可以将图像过渡得柔和一些。
  89.         // Each save should be balanced with a call to restore().
  90.         camera.save();
  91.         Matrix matrix = new Matrix();
  92.         // rotate
  93.         camera.rotateX(rotateX);
  94.         camera.rotateY(rotateY);
  95.         camera.rotateZ(rotateZ);
  96.         // translate
  97.         camera.translate(0, 0, translateZ);
  98.         camera.getMatrix(matrix);
  99.         // 恢复到之前的初始状态。
  100.         camera.restore();
  101.         // 设置图像处理的中心点
  102.         matrix.preTranslate(tmpBit.getWidth() >> 1, tmpBit.getHeight() >> 1);
  103.         matrix.preSkew(skewX, skewY);
  104.         // matrix.postSkew(skewX, skewY);
  105.         // 直接setSkew(),则前面处理的rotate()、translate()等等都将无效。
  106.         // matrix.setSkew(skewX, skewY);
  107.         // 2.通过矩阵生成新图像(或直接作用于Canvas)
  108.         Log.d(“ANDROID_LAB”, “width=” + tmpBit.getWidth() + “ height=” + tmpBit.getHeight());
  109.         Bitmap newBit = null;
  110.         try {
  111.             // 经过矩阵转换后的图像宽高有可能不大于0,此时会抛出IllegalArgumentException
  112.             newBit = Bitmap.createBitmap(tmpBit, 0, 0, tmpBit.getWidth(), tmpBit.getHeight(), matrix, true);
  113.         } catch (IllegalArgumentException iae) {
  114.             iae.printStackTrace();
  115.         }
  116.         if (newBit != null) {
  117.             imgResult.setImageBitmap(newBit);
  118.         }
  119.     }
  120.  
  121.     @Override
  122.     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
  123.         if (seekBar == seekbarXRotate) {
  124.             txtXRotate.setText(progress + “゜”);
  125.             rotateX = progress;
  126.         } else if (seekBar == seekbarYRotate) {
  127.             txtYRotate.setText(progress + “゜”);
  128.             rotateY = progress;
  129.         } else if (seekBar == seekbarZRotate) {
  130.             txtZRotate.setText(progress + “゜”);
  131.             rotateZ = progress;
  132.         } else if (seekBar == seekbarXSkew) {
  133.             skewX = (progress - 100) * 1.0f / 100;
  134.             txtXTranslate.setText(String.valueOf(skewX));
  135.         } else if (seekBar == seekbarYSkew) {
  136.             skewY = (progress - 100) * 1.0f / 100;
  137.             txtYTranslate.setText(String.valueOf(skewY));
  138.         } else if (seekBar == seekbarZTranslate) {
  139.             translateZ = progress - 100;
  140.             txtZTranslate.setText(String.valueOf(translateZ));
  141.         }
  142.         refreshImage();
  143.     }
  144.  
  145.     @Override
  146.     public void onStartTrackingTouch(SeekBar seekBar) {
  147.  
  148.     }
  149.  
  150.     @Override
  151.     public void onStopTrackingTouch(SeekBar seekBar) {
  152.  
  153.     }
  154. }

Create simple effects for your images (IV) - 3D Projection

在 Android SDK 中有两种 Camera classes。一个是 android.hardware.Camera,这是用来操控相机功能的类别。另一个是 android.graphics.Camera,这是什麼东西?今天我们就要来研究一下,这个类别能帮我们做些什麼事。

android.graphics.Camera 是一个可以让你将 2D 物件在 3D 空间中移动,并将在其移动后的结果,画在萤幕上的类别。

听起来很有趣,是吗?例如,最上面那张美女图,你可以看出来,他是将原本的图,以 Y 轴為轴心,旋转约 30 度后,所画出来的结果。

打开 android.graphics.Camera 的说明文件,你会发现,这个文件中只有下面这些 APIs 列表,什麼说明都没有。

1. //Public Constructors
2. Camera()
3. //Public Methods
4. void applyToCanvas(Canvas canvas)
5. float dotWithNormal(float dx, float dy, float dz)
6. void getMatrix(Matrix matrix)
7. void restore()
8. void rotateX(float deg)
9. void rotateY(float deg)
10. void rotateZ(float deg)
11. void save()
12. void translate(float x, float y, float z)

//Public Constructors Camera() //Public Methods void applyToCanvas(Canvas canvas) float dotWithNormal(float dx, float dy, float dz) void getMatrix(Matrix matrix) void restore() void rotateX(float deg) void rotateY(float deg) void rotateZ(float deg) void save() void translate(float x, float y, float z)

不过,从这些 APIs 的名称与参数,你应该可以猜出一些端倪。没错,这个 Camera class,其实是个 helper class。他提供一些 APIs ,让你控制要如何在 3D 空间中移动,最后再產生出合适的 Matrix ,让你套用到 Canvas 的座标体系上。关于 Matrix,我在 帮图片加上影像特效 (I) - 阴影特效 已经介绍过他的强大,还不知道的,先读一下这篇。

用个例子来解释这个 Camera 类别的用法,是最适当的。底下这个简单的程式片段的结果,就是最上面那张图。其中的 m_bmp 就是原本的美女图。

1. camera = new Camera();
2. camera.translate(0, 0, 50);
3. camera.rotateY(30);
4. Matrix matrix3D = new Matrix();
5. camera.getMatrix(matrix3D);
6.
7. canvas.save();
8. canvas.translate(100, 100);
9. canvas.concat(matrix3D);
10.
11. canvas.drawBitmap(m_bmp, 0, 0, null);
12. canvas.restore();

camera = new Camera(); camera.translate(0, 0, 50); camera.rotateY(30); Matrix matrix3D = new Matrix(); camera.getMatrix(matrix3D); canvas.save(); canvas.translate(100, 100); canvas.concat(matrix3D); canvas.drawBitmap(m_bmp, 0, 0, null); canvas.restore();

从这个范例程式中,我们知道,你可以利用 Camera.translate() 及 Camera.rotateXXX() 等 APIs 在 3D 空间中移动。其实,这些 APIs 就是在操作 Matrix 的内容。最后,你只要呼叫 Camera.getMatrix() 即可将这 Matrix 的内容抓出,并套到 Canvas 上。

在 Android ,要做出 3D 的效果,你当然可以用 OpenGL 的函式。不过,如果你需要更快的显示速度,或者只是要做个简单的 3D 特效,那千万不要忘了这个 android.graphics.Camera。