在 SurfaceFlinger 中,Source Crop 是用于指定源图像的裁剪区域的一个概念。Source Crop 可以理解为是一个矩形区域,它定义了源图像中要被渲染到目标区域的部分。在 Android 中,Source Crop 通常用于实现屏幕分辨率适应和缩放等功能。
在 SurfaceFlinger 中,每个图层都有一个 Source Crop 的属性,用于指定该图层在源图像中的裁剪区域。当 SurfaceFlinger 按照图层顺序将图层合成到最终的目标缓冲区时,它会根据每个图层的 Source Crop 和目标区域的尺寸来计算出该图层在目标区域中的显示位置和大小。这样,就可以实现对源图像的裁剪和缩放等操作。
在 Android 应用程序中,我们可以使用 SurfaceView 或者 TextureView 等组件来创建一个图层,并在它上面绘制自己的图形。在创建图层时,我们可以通过设置组件的 SurfaceHolder 或者 SurfaceTexture 等对象的 Source Crop 属性来指定图层的裁剪区域,从而实现对图层的缩放和裁剪等操作。
以下是一个示例代码,展示了如何使用 SurfaceView 和 SurfaceHolder 来创建一个图层,并设置其 Source Crop 属性:
javaCopy
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder;
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
// 获取 SurfaceHolder 对象
holder = getHolder();
// 添加回调函数
holder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// 获取 Canvas 对象
Canvas canvas = holder.lockCanvas();
// 设置 Source Crop 属性
Rect sourceCrop = new Rect(0, 0, 400, 400);
holder.setFixedSize(sourceCrop.width(), sourceCrop.height());
// 绘制图形
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawRect(sourceCrop, paint);
// 解锁画布,并提交绘制内容
holder.unlockCanvasAndPost(canvas);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// Do nothing
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Do nothing
}
}
在上面的代码中,我们创建了一个自定义的 SurfaceView 组件,并实现了 SurfaceHolder.Callback 接口的三个回调函数。在 surfaceCreated() 回调函数中,我们获取了 SurfaceHolder 对象并通过 lockCanvas() 方法获取了一个 Canvas 对象。然后,我们设置了 Source Crop 属性,并使用 Canvas 绘制了一个红色矩形。最后,我们调用 unlockCanvasAndPost() 方法解锁画布,并提交绘制内容。
需要注意的是,在设置 Source Crop 属性时,我们使用了 SurfaceHolder 的 setFixedSize() 方法来指定目标区域的尺寸。这是因为,Source Crop 只能裁剪图像,不能改变图像的大小。因此,如果要实现缩放等操作,必须通过设置目标区域的尺寸来实现。
通过setFixedSize可以设置绘制的大小,这里我们进行测试,在一个activity中准备3个按钮,点击按钮来绘制不同大小的画布,看看效果。
首先看看屏幕的大小
adb shell wm size
Physical size: 1600x2560
准备设置3个大小的画布来进行试验
1 480X800
2 1600x2560
3 2600x3560
package com.example.testsize;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(view -> {
Intent intent = new Intent(MainActivity.this, newActivity.class);
intent.putExtra("id", 1);
startActivity(intent);
});
findViewById(R.id.button2).setOnClickListener(view -> {
Intent intent = new Intent(MainActivity.this, newActivity.class);
intent.putExtra("id", 2);
startActivity(intent);
});
findViewById(R.id.button3).setOnClickListener(view -> {
Intent intent = new Intent(MainActivity.this, newActivity.class);
intent.putExtra("id", 3);
startActivity(intent);
});
}
}
newActivity代码
package com.example.testsize;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class newActivity extends AppCompatActivity {
private SurfaceView surfaceView;
private int gameWidth = 480; // 游戏画面宽度
private int gameHeight = 800; // 游戏画面高度
private int gameFps = 3; // 游戏画面帧率 60
private int squareSize = 100; // 小方块尺寸
private int squareX = 20; // 小方块横向位置
private int squareX2 = 1560; // 小方块横向位置2
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new);
//get data
Intent intent = getIntent();
int id = intent.getIntExtra("id", 0);
if (id == 2) {
gameWidth = 1600;
gameHeight = 2560;
} else if (id == 3) {
gameWidth = 2600;
gameHeight = 3560;
}
// 获取 SurfaceView 组件
surfaceView = findViewById(R.id.surfaceView);
// 设置游戏画面的尺寸和绘制速度等参数
surfaceView.getHolder().setFixedSize(gameWidth, gameHeight);
surfaceView.getHolder().setFormat(PixelFormat.RGBA_8888);
surfaceView.getHolder().setKeepScreenOn(true);
surfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT);
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
// 游戏画面创建时的初始化操作
new Thread(new Runnable() {
@Override
public void run() {
// 获取 Canvas 组件
Canvas canvas = surfaceView.getHolder().lockCanvas();
// 在 Canvas 上绘制游戏画面
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawRect(squareX, gameHeight / 2 - squareSize / 2, squareX + squareSize, gameHeight / 2 + squareSize / 2, paint);
//draw rect 2
canvas.drawRect(squareX2, gameHeight / 2 - squareSize / 2, squareX2 + squareSize, gameHeight / 2 + squareSize / 2, paint);
// 释放 Canvas 组件
surfaceView.getHolder().unlockCanvasAndPost(canvas);
// 循环更新游戏画面
while (true) {
/*
// 获取 Canvas 组件
Canvas canvas1 = surfaceView.getHolder().lockCanvas();
// 在 Canvas 上绘制游戏画面
Paint paint1 = new Paint();
paint1.setColor(Color.RED);
canvas1.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
canvas1.drawRect(squareX, gameHeight / 2 - squareSize / 2, squareX + squareSize, gameHeight / 2 + squareSize / 2, paint1);
// 更新小方块位置
squareX += 5;
if (squareX > gameWidth) {
squareX = 0;
}
// 释放 Canvas 组件
surfaceView.getHolder().unlockCanvasAndPost(canvas1);
*/
// 控制游戏画面的帧率
try {
Thread.sleep(1000 * 100 / gameFps);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// 游戏画面尺寸发生变化时的操作
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// 游戏画面销毁时的操作
}
});
}
}
布局activity_new.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".newActivity">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
试验效果图
截取了480X800,由于比屏幕小,在屏幕上进行了放大
dumpsys SurfaceFlinger
Display 4630947232161729154 (active) HWC layers:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Layer name
Z | Window Type | Layer Class | Comp Type | Transform | Disp Frame (LTRB) | Source Crop (LTRB) | Frame Rate (Explicit) (Seamlessness) [Focused] [FrameBooster]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SurfaceView[com.example.testsize/com[...]testsize.newActivity]@0(BLAST)#21860
rel 0 | 0 | 0 | DEVICE | 0 | 0 187 1600 2458 | 0.0 0.0 480.0 800.0 | [*] [ ]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
com.example.testsize/com.example.testsize.newActivity$_15842#21855
rel 0 | 1 | 0 | DEVICE | 0 | 0 0 1600 2560 | 0.0 0.0 1600.0 2560.0 | [*] [ ]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
MSHandler:com.example.testsize/com.e[...]ize.newActivity@709a0f3$_15842#21868
rel 0 | 2 | 0 | DEVICE | 0 | 630 0 970 163 | 0.0 9.0 340.0 172.0 | [ ] [ ]
2. 1600x2560,和屏幕大小一致,
Display 4630947232161729154 (active) HWC layers:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Layer name
Z | Window Type | Layer Class | Comp Type | Transform | Disp Frame (LTRB) | Source Crop (LTRB) | Frame Rate (Explicit) (Seamlessness) [Focused] [FrameBooster]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SurfaceView[com.example.testsize/com[...]testsize.newActivity]@0(BLAST)#21919
rel 0 | 0 | 0 | DEVICE | 0 | 0 187 1600 2458 | 0.0 0.0 1600.0 2560.0 | [*] [ ]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
com.example.testsize/com.example.testsize.newActivity$_15842#21914
rel 0 | 1 | 0 | DEVICE | 0 | 0 0 1600 2560 | 0.0 0.0 1600.0 2560.0 | [*] [ ]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
MSHandler:com.example.testsize/com.e[...]ize.newActivity@8ba4b78$_15842#21927
rel 0 | 2 | 0 | DEVICE | 0 | 630 0 970 163 | 0.0 9.0 340.0 172.0 | [ ] [ ]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3. 画布是2600x3560,大于屏幕大小,在显示到屏幕的时候进行了缩小处理
Display 4630947232161729154 (active) HWC layers:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Layer name
Z | Window Type | Layer Class | Comp Type | Transform | Disp Frame (LTRB) | Source Crop (LTRB) | Frame Rate (Explicit) (Seamlessness) [Focused] [FrameBooster]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SurfaceView[com.example.testsize/com[...]testsize.newActivity]@0(BLAST)#21959
rel 0 | 0 | 0 | DEVICE | 0 | 0 187 1600 2458 | 0.0 0.0 2600.0 3560.0 | [*] [ ]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
com.example.testsize/com.example.testsize.newActivity$_15842#21954
rel 0 | 1 | 0 | DEVICE | 0 | 0 0 1600 2560 | 0.0 0.0 1600.0 2560.0 | [*] [ ]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
实际效果 3截图