需要图片集和源码请点赞关注收藏后评论区留言~~~
一、转换位图的像素色彩
给图片添加装饰物,只是在局部变换,如果想让图片一边保持轮廓一边改变色彩,就要深入图像的每个像素点,将这些像素点统统采取某种算法修改一番,在像素级别更改图像的话,要先把图片转换成位图对象再进一步加工位图对象,此时用到了位图工具Bitmap 主要方法如下
1:createBitmap 创建一个新位图
2:getPixels 获取位图对象所有点的像素数组
3:setPixels 设置位图对象所有点的像素数组
效果如下 可以将一张图片以多种色彩效果显示出来
代码如下
Java类
package com.example.picture; import androidx.appcompat.app.AppCompatActivity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.Spinner; import com.example.picture.util.BitmapUtil; public class BitmapPixelActivity extends AppCompatActivity { private ImageView iv_picture; // 声明一个图像视图对象 private Bitmap mOriginBitmap; // 原始位图 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bitmap_pixel); iv_picture = findViewById(R.id.iv_picture); mOriginBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.butterfly); initColorSpinner(); // 初始化色彩模式下拉框 } // 初始化色彩模式下拉框 private void initColorSpinner() { ArrayAdapter<String> colorAdapter = new ArrayAdapter<>(this, R.layout.item_select, colorNameArray); Spinner sp_color = findViewById(R.id.sp_color); sp_color.setPrompt("请选择色彩模式"); sp_color.setAdapter(colorAdapter); sp_color.setOnItemSelectedListener(new ColorSelectedListener()); sp_color.setSelection(0); } private String[] colorNameArray = {"原色", "黑白", "底片", "怀旧", "模糊"}; class ColorSelectedListener implements AdapterView.OnItemSelectedListener { public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { if (arg2 == 0) { // 原色 iv_picture.setImageBitmap(mOriginBitmap); // 设置图像视图的位图对象 } else if (arg2 == 1) { // 黑白 Bitmap bitmap = BitmapUtil.convertBlack(mOriginBitmap); // 转换为黑白效果 iv_picture.setImageBitmap(bitmap); // 设置图像视图的位图对象 } else if (arg2 == 2) { // 底片 Bitmap bitmap = BitmapUtil.convertNegative(mOriginBitmap); // 转换为底片效果 iv_picture.setImageBitmap(bitmap); // 设置图像视图的位图对象 } else if (arg2 == 3) { // 怀旧 Bitmap bitmap = BitmapUtil.convertOld(mOriginBitmap); // 转换为怀旧效果 iv_picture.setImageBitmap(bitmap); // 设置图像视图的位图对象 } else if (arg2 == 4) { // 模糊 Bitmap bitmap = BitmapUtil.convertBlur(mOriginBitmap); // 转换为模糊效果 iv_picture.setImageBitmap(bitmap); // 设置图像视图的位图对象 } } public void onNothingSelected(AdapterView<?> arg0) {} } }
XML文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="40dp"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:paddingLeft="5dp" android:gravity="center" android:text="请选择色彩模式" android:textColor="@color/black" android:textSize="17sp" /> <Spinner android:id="@+id/sp_color" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:spinnerMode="dialog" /> </LinearLayout> <ImageView android:id="@+id/iv_picture" android:layout_width="match_parent" android:layout_height="200dp" android:src="@drawable/butterfly" /> </LinearLayout>
二、裁剪位图内部区域
createBitmap方法不仅可以创建空白位图,甚至能从原位图上截取一部分下来,裁剪出来的新位图来自原始位图,为了清楚的标记它在原位图的位置,可在图像视图上方覆盖新的图层,然后新图层先画一遍半透明的阴影,再画裁剪的位图部分,观察新老图层就可以看出裁剪的部位 效果如下
可以在下拉框中红选择裁剪不同区域并且保留图片
代码如下
Java类
package com.example.picture; import android.graphics.Bitmap; import android.graphics.Rect; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.Spinner; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import com.example.picture.util.BitmapUtil; import com.example.picture.util.DateUtil; import com.example.picture.widget.CropImageView; public class BitmapCutActivity extends AppCompatActivity { private CropImageView civ_over; // 声明一个裁剪视图对象 private ImageView iv_old; // 声明一个原始图片的图像视图对象 private ImageView iv_new; // 声明一个最新图片的图像视图对象 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bitmap_cut); civ_over = findViewById(R.id.civ_over); iv_old = findViewById(R.id.iv_old); iv_new = findViewById(R.id.iv_new); findViewById(R.id.btn_save_image).setOnClickListener(v -> { civ_over.setVisibility(View.GONE); Bitmap bitmap = civ_over.getCropBitmap(); // 获取裁剪视图处理后的位图 iv_new.setImageBitmap(bitmap); // 设置图像视图的位图对象 // 生成图片文件的保存路径 String path = String.format("%s/%s.jpg", getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(), DateUtil.getNowDateTime()); BitmapUtil.saveImage(path, bitmap); // 把位图保存为图片文件 BitmapUtil.notifyPhotoAlbum(this, path); // 通知相册来了张新图片 Toast.makeText(this, "成功保存图片文件:" + path, Toast.LENGTH_SHORT).show(); initZoneSpinner(); // 初始化裁剪区域下拉框 }); iv_old.setDrawingCacheEnabled(true); // 开启位图视图的绘图缓存 iv_old.setImageResource(R.drawable.butterfly); // 设置图像视图的资源编号 new Handler(Looper.myLooper()).postDelayed(() -> initZoneSpinner(), 200); } // 初始化裁剪区域下拉框 private void initZoneSpinner() { ArrayAdapter<String> zoneAdapter = new ArrayAdapter<>(this, R.layout.item_select, zoneNameArray); Spinner sp_zone = findViewById(R.id.sp_zone); sp_zone.setPrompt("请选择裁剪区域"); sp_zone.setAdapter(zoneAdapter); sp_zone.setOnItemSelectedListener(new ZoneSelectedListener()); sp_zone.setSelection(0); } private String[] zoneNameArray = {"不裁剪", "中间", "左上角", "右上角", "左下角", "右下角"}; class ZoneSelectedListener implements AdapterView.OnItemSelectedListener { public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { civ_over.setVisibility(arg2==0?View.GONE:View.VISIBLE); Bitmap bitmap = iv_old.getDrawingCache(); // 从绘图缓存获取位图对象 int width = bitmap.getWidth(), height = bitmap.getHeight(); civ_over.setOrigBitmap(bitmap); // 设置裁剪视图的原始位图 // 以下依据裁剪区域分别设置裁剪视图的位图边界 if (arg2 == 1) { // 中间 civ_over.setBitmapRect(new Rect(width/4, height/4, width/2, height/2)); } else if (arg2 == 2) { // 左上角 civ_over.setBitmapRect(new Rect(0, 0, width/2, height/2)); } else if (arg2 == 3) { // 右上角 civ_over.setBitmapRect(new Rect(width/2, 0, width/2, height/2)); } else if (arg2 == 4) { // 左下角 civ_over.setBitmapRect(new Rect(0, height/2, width/2, height/2)); } else if (arg2 == 5) { // 右下角 civ_over.setBitmapRect(new Rect(width/2, height/2, width/2, height/2)); } } public void onNothingSelected(AdapterView<?> arg0) {} } }
XML文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="40dp"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:paddingLeft="5dp" android:gravity="center" android:text="请选择裁剪区域" android:textColor="@color/black" android:textSize="17sp" /> <Spinner android:id="@+id/sp_zone" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:spinnerMode="dialog" /> </LinearLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="200dp" > <ImageView android:id="@+id/iv_old" android:layout_width="match_parent" android:layout_height="match_parent" /> <com.example.picture.widget.CropImageView android:id="@+id/civ_over" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/transparent" android:scaleType="fitXY" android:visibility="gone" /> </FrameLayout> <Button android:id="@+id/btn_save_image" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="保存图片" android:textColor="@color/black" android:textSize="17sp" /> <ImageView android:id="@+id/iv_new" android:layout_width="match_parent" android:layout_height="200dp" android:scaleType="centerInside" /> </LinearLayout>
三、利用矩阵变换位图
可以利用矩阵工具Matrix对图片完成缩放 旋转 平移等变换操作 常用方法如下
postScale 指定横纵坐标两个方向的缩放比率
postRotate 指定旋转角度
postTranslate 指定横纵坐标两个方向的偏移大小
postSkew 指定横纵坐标两个方向的倾斜比例
效果如下 可在下拉框中选择旋转角度以及缩放比例、是否左右反转图像等等 同样可以保存图片
代码如下
Java类
package com.example.picture; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Environment; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.Spinner; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import com.example.picture.util.BitmapUtil; import com.example.picture.util.DateUtil; import com.example.picture.widget.BitmapView; public class BitmapChangeActivity extends AppCompatActivity { private BitmapView bv_image; // 声明一个位图视图对象 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bitmap_change); CheckBox ck_flip = findViewById(R.id.ck_flip); bv_image = findViewById(R.id.bv_image); ck_flip.setOnCheckedChangeListener((buttonView, isChecked) -> { bv_image.flip(); // 左右翻转图像 }); findViewById(R.id.btn_save_image).setOnClickListener(v -> { Bitmap bitmap = bv_image.getDrawingCache(); // 从绘图缓存获取位图对象 // 生成图片文件的保存路径 String path = String.format("%s/%s.jpg", getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(), DateUtil.getNowDateTime()); BitmapUtil.saveImage(path, bitmap); // 把位图保存为图片文件 BitmapUtil.notifyPhotoAlbum(this, path); // 通知相册来了张新图片 Toast.makeText(this, "成功保存图片文件:" + path, Toast.LENGTH_LONG).show(); }); initScaleSpinner(); // 初始化缩放比率下拉框 initRotateSpinner(); // 初始化旋转角度下拉框 } @Override protected void onStart() { super.onStart(); bv_image.setDrawingCacheEnabled(true); // 开启位图视图的绘图缓存 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.butterfly); bv_image.setImageBitmap(bitmap); // 设置位图视图的位图对象 } @Override protected void onStop() { super.onStop(); bv_image.setDrawingCacheEnabled(false); // 关闭位图视图的绘图缓存 } // 初始化缩放比率下拉框 private void initScaleSpinner() { ArrayAdapter<String> scaleAdapter = new ArrayAdapter<>(this, R.layout.item_select, scaleArray); Spinner sp_scale = findViewById(R.id.sp_scale); sp_scale.setPrompt("请选择缩放比率"); sp_scale.setAdapter(scaleAdapter); sp_scale.setOnItemSelectedListener(new ScaleSelectedListener()); sp_scale.setSelection(3); } private String[] scaleArray = {"0.25", "0.5", "0.75", "1.0", "1.5", "2.0", "4.0"}; class ScaleSelectedListener implements OnItemSelectedListener { public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // 设置缩放比例 bv_image.setScaleRatio(Float.parseFloat(scaleArray[arg2]), true); } public void onNothingSelected(AdapterView<?> arg0) {} } // 初始化旋转角度下拉框 private void initRotateSpinner() { ArrayAdapter<String> rotateAdapter = new ArrayAdapter<>(this, R.layout.item_select, rotateArray); Spinner sp_rotate = findViewById(R.id.sp_rotate); sp_rotate.setPrompt("请选择旋转角度"); sp_rotate.setAdapter(rotateAdapter); sp_rotate.setOnItemSelectedListener(new RotateSelectedListener()); sp_rotate.setSelection(0); } private String[] rotateArray = {"0", "45", "90", "135", "180", "225", "270", "315"}; class RotateSelectedListener implements OnItemSelectedListener { public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // 设置旋转角度 bv_image.setRotateDegree(Integer.parseInt(rotateArray[arg2]), true); } public void onNothingSelected(AdapterView<?> arg0) {} } }
XML文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="5dp" android:orientation="horizontal" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="缩放比率" android:textColor="@color/black" android:textSize="17sp" /> <Spinner android:id="@+id/sp_scale" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:spinnerMode="dialog" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="旋转角度" android:textColor="@color/black" android:textSize="17sp" /> <Spinner android:id="@+id/sp_rotate" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:spinnerMode="dialog" /> </LinearLayout> <CheckBox android:id="@+id/ck_flip" android:layout_width="match_parent" android:layout_height="40dp" android:text="是否左右翻转图像" android:textColor="@color/black" android:textSize="17sp" /> <com.example.picture.widget.BitmapView android:id="@+id/bv_image" android:layout_width="match_parent" android:layout_height="200dp" android:background="@color/white" /> <Button android:id="@+id/btn_save_image" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="保存图片" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout>
创作不易 觉得有帮助请点赞关注收藏~~~