实训第一周(1)
实训项目:研发一个可以通过键盘和语音实现输入个性化手写字体的聊天应用,并添加多点触控交互技术。
我本周的任务是:根据触摸位置与中心位置的偏置实现相应的字体局部变形。
这个功能的主要作用是实现异形文字,即同一文字的不同外形。比如即使是同一个人把一个字母写两遍,它们也不会完全相同。
1.文字手写绘入及保存:
绘制我们使用了canvas画布,实现非常简单,主要在ImageView的监听器中定义如下
showBitmap = Bitmap.createBitmap(iv_canvas.getWidth(),
iv_canvas.getHeight(), Bitmap.Config.ARGB_8888);
show_canvas = new Canvas(showBitmap);
show_canvas.drawColor(Color.WHITE);
图片的保存
/*
* 保存图片到SD卡上
*/
protected void saveBitmap() {
try {
// 保存图片到SD卡上
File file = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".png");
FileOutputStream stream = new FileOutputStream(file);
baseBitmap.compress(CompressFormat.PNG, 100, stream);
Toast.makeText(MainActivity.this, "保存图片成功", Toast.LENGTH_LONG).show();
// Android设备Gallery应用只会在启动的时候扫描系统文件夹
// 这里模拟一个媒体装载的广播,用于使保存的图片可以在Gallery中查看
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MEDIA_MOUNTED);
intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));
sendBroadcast(intent);
} catch (Exception e) {
Toast.makeText(MainActivity.this, "保存图片失败", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
2.交互式变形
一开始我们从网上找各种方法,一个比较好的是canvas的drawBitmapMesh网格变形方法。但经过大量的实验发现没法把变形后的bitmap提取出来,但我们必须要保存它,所以最后放弃了。
之后我自己写了一个比网格变形粗糙的方法,但因为效果比较显著且简单,所以就用了这个方法
方法如图所示:中间圆点为触摸点,根据它与图片中心的偏置来相应的拉扯图片(将每行、每列像素放大),然后将新图片每个点的颜色反向映射到原图像对应点的颜色。
protected int[][] distort(int[][] pixels_copy, int dx, int dy, int row, int col) {
int[][] result_pixels1 = new int[row][col];
int[][] result_pixels2 = new int[row][col];
int currentY, currentX;//当前要拉伸的行数
int xAdd1, yAdd1, xAdd, yAdd;
//逐行拉伸
for (currentY = 0; currentY < row; currentY++) {
//对于每一行要扩展的像素数
if (currentY <= dy) {
xAdd = currentY * Math.abs(dx - col / 2) / dy;
} else {
xAdd = (row - currentY) * Math.abs(dx - col / 2) / (row - dy);
}
//判断往左还是往右拉伸
if (dx <= (col / 2)) {
//往左拉伸
xAdd1 = xAdd;
} else {
xAdd1 = 0;
}
//反向映射当前像素点的颜色
for (int x = 0; x < col; x++) {
int x0 = (x + xAdd1) * col / (col + xAdd);//对应的原图x坐标
result_pixels1[currentY][x] = pixels_copy[currentY][x0];
}
}
//逐列拉伸
for (currentX = 0; currentX < col; currentX++) {
//对于每一列要扩展的像素数
if (currentX <= dx) {
yAdd = currentX * Math.abs(dy - row / 2) / dx;
} else {
yAdd = (col - currentX) * Math.abs(dy - row / 2) / (col - dx);
}
//判断往上还是往下拉伸
if (dy <= row / 2) {
yAdd1 = yAdd;
} else {
yAdd1 = 0;
}
//反向映射颜色值
for (int y = 0; y < row; y++) {
int y0 = (y + yAdd1) * row / (row + yAdd);
result_pixels2[y][currentX] = result_pixels1[y0][currentX];
}
}
return result_pixels2;
}
效果如下: