Android App开发之位图加工Bitmap中转换位图的像素色彩、裁剪内部区域、利用矩阵变换位图的讲解及实战(附源码和演示)
需要图片集和源码请点赞关注收藏后评论区留言~~~
一、转换位图的像素色彩
给图片添加装饰物,只是在局部变换,如果想让图片一边保持轮廓一边改变色彩,就要深入图像的每个像素点,将这些像素点统统采取某种算法修改一番,在像素级别更改图像的话,要先把图片转换成位图对象再进一步加工位图对象,此时用到了位图工具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; // 原始位图@Overrideprotected 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"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="40dp"><TextViewandroid:layout_width="wrap_content"android:layout_height="match_parent"android:paddingLeft="5dp"android:gravity="center"android:text="请选择色彩模式"android:textColor="@color/black"android:textSize="17sp" /><Spinnerandroid:id="@+id/sp_color"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:spinnerMode="dialog" /></LinearLayout><ImageViewandroid: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; // 声明一个最新图片的图像视图对象@Overrideprotected 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" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="40dp"><TextViewandroid:layout_width="wrap_content"android:layout_height="match_parent"android:paddingLeft="5dp"android:gravity="center"android:text="请选择裁剪区域"android:textColor="@color/black"android:textSize="17sp" /><Spinnerandroid:id="@+id/sp_zone"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:spinnerMode="dialog" /></LinearLayout><FrameLayoutandroid:layout_width="match_parent"android:layout_height="200dp" ><ImageViewandroid:id="@+id/iv_old"android:layout_width="match_parent"android:layout_height="match_parent" /><com.example.picture.widget.CropImageViewandroid: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><Buttonandroid:id="@+id/btn_save_image"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="保存图片"android:textColor="@color/black"android:textSize="17sp" /><ImageViewandroid: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; // 声明一个位图视图对象@Overrideprotected 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(); // 初始化旋转角度下拉框}@Overrideprotected void onStart() {super.onStart();bv_image.setDrawingCacheEnabled(true); // 开启位图视图的绘图缓存Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.butterfly);bv_image.setImageBitmap(bitmap); // 设置位图视图的位图对象}@Overrideprotected 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" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:paddingLeft="5dp"android:orientation="horizontal" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="缩放比率"android:textColor="@color/black"android:textSize="17sp" /><Spinnerandroid:id="@+id/sp_scale"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:spinnerMode="dialog" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="旋转角度"android:textColor="@color/black"android:textSize="17sp" /><Spinnerandroid:id="@+id/sp_rotate"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:spinnerMode="dialog" /></LinearLayout><CheckBoxandroid: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.BitmapViewandroid:id="@+id/bv_image"android:layout_width="match_parent"android:layout_height="200dp"android:background="@color/white" /><Buttonandroid: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>
创作不易 觉得有帮助请点赞关注收藏~~~
Android App开发之位图加工Bitmap中转换位图的像素色彩、裁剪内部区域、利用矩阵变换位图的讲解及实战(附源码和演示)相关推荐
- 【Android App】二维码的讲解及生成属于自己的二维码实战(附源码和演示 超详细必看)
需要全部代码请点赞关注收藏后评论区留言~~~ 一.二维码基本内容介绍 条形码只能表达十几位数字编码,无法表示更复杂的数据. 二维码在二维方格上描出一个个黑点,从而表达更丰富的信息. 二维码早已在手机A ...
- Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
运行有问题或需要源码请点赞关注收藏后评论区留言~~~ 一.三维投影 OpenGL,定义了跨语言跨平台的图形程序接口,对于Android开发者来说,OpenGL就是用来绘制三维图形的技术手段.当然Ope ...
- Android App开发实战项目之模仿美图秀秀的抠图工具(附源码和演示视频 简单易懂 可直接使用)
需要图片集和源码请点赞关注收藏后评论区留言~~~ 所谓抠图神器,就是从一副图片中扣出用户想要的某块区域 一.需求描述 美图的修图功能如此强大,离不开专业的图片加工技术,抠图便是其中重要的一项功能.在A ...
- 【Android App】人脸识别中扫描识别二维码实战解析(附源码和演示 超详细)
需要源码请点赞关注收藏后评论区留言私信~~~ 一.扫描识别二维码 不仅可以利用zxing库生成二维码,同样利用zxing库可以扫描二维码并解析得到原始文本,此时除了给build.gradle添加如下一 ...
- Android App开发实战项目之仿手机QQ动感影集动画播放(附源码和演示视频 可直接使用)
需要图片集和源码请点赞关注收藏后评论区留言~~~ 动感影集就是只要用户添加一张图片,动感影集就能给每张图片渲染不同的动画效果,让原本静止的图片变得活泼起来,辅以各种精致的动画特效,营造一种赏心悦目的感 ...
- Android App开发实战项目之仿喜马拉雅的听说书App实现(超详细 附源码和演示视频)
需要全部源码请点赞关注收藏后评论区留下QQ~~~ 一.需求分析 用户不仅能在平台上收听音频,还能成为内容创作者,总之长音频分享平台需要满足两种角色的使用:一种是作为内容创作者发布自己的音频,另一种是作 ...
- Android App开发实战项目之大头贴App功能实现(附源码和演示 简单易上手)
需要图片集和源码请点赞关注收藏后评论区留言~~~ 一.需求描述 大头贴App有两个特征,第一个是头要大,拿来一张照片后把人像区域裁剪出来,这样新图片里的人头才会比较大,第二个是在周围贴上装饰物,而且装 ...
- 【Android App】人脸识别中使用Opencv比较两张人脸相似程度实战(附源码和演示 超详细)
需要全部代码请点赞关注收藏后评论区留言私信~~~ 一.比较两张人脸的相似程度 直方图由一排纵向的竖条或者竖线组成,横轴代表数据类型,纵轴代表数据多少. 图像直方图经常应用于特征提取.图像匹配等方面. ...
- 【Android App】人脸识别中借助摄像头和OpenCV实时检测人脸讲解及实战(附源码和演示 超详细)
需要全部代码请点赞关注收藏后评论区留言私信~~~ 一.借助摄像头实时检测人脸 与Android自带的人脸检测器相比,OpenCV具备更强劲的人脸识别功能,它可以通过摄像头实时检测人脸,实时检测的预览空 ...
最新文章
- java catch 空指针异常_关于Java:捕获空指针异常
- [vue] SSR解决了什么问题?有做过SSR吗?你是怎么做的?
- 福建省计算机中职类高考400分多少名,重要参考!福建高职分类各院校近两年招生计划及分数线汇总来了,快收藏...
- Python 批量重命名文件
- 制作linux镜像时哪些文件时必须打包的,如何将linux系统制作成iso镜像文件?通过Mondo Rescue工具将linux系统制作成ISO镜像...
- 计算机中丢失了gdiplus.dll,解决 “计算机中丢失gdiplus.dll”
- 善领dsa android正式版,善领dsa_善领dsa安卓版_善领dsa2016最新版p57
- 第一篇:手把手教你移植任天堂,没有声音、无需外置SD卡、可使用独立按键也可使用外置手柄,本人使用的芯片为ESP32,移植到STM32均可使用。(本篇主要介绍nes_main.h这个文件)
- 3dmax外挂神器更新了|3dmax外挂在过去几年里,食住玩都更新记录了3dmax外挂的什么功能?
- 海淘尺码表,贡献给论坛买衣服裤子鞋子的朋友
- POJ 1201 Intervals(差分约束)
- nested exception is java.lang.NumberFormatException: For input string: NaN
- 全球及中国图书出版发行业营销策略与运行前景分析报告2022版
- 给你一个字符串,删除其中的不是英文字母的符号,也就是说除了英文字母之外的字符都应该删除,请你输出删除后的字符串。
- VLIW的前世今生:为什么DL加速器都青睐于它
- 西餐餐饮文化、简单鸡尾酒调制~~DIY的力量无穷
- 英语中容易混淆的单词发音: 一
- 斐讯路由器宽带运营商服务器,新版斐讯p.to路由器的设置教程
- Android手机平板根目录详解
- 计算机网络笔试面试题目大全
热门文章
- STM32 SPI TX FIFO处理
- element is not attached to the page document报错解决办法
- GZIP文件格式简介
- PyTorch运行加载数据后占有大量C盘空间如何释放
- From line 6, column 36 to line 6, column 71: Cannot apply ‘-‘ to arguments of type ‘<VARCHAR(214748
- 小学计算机基础知识汇总,电脑基础知识:内存条知识大全,看完小学生都了解...
- Jolla 超额完成开源平板电脑众筹
- Arndale Octa 5420网络设置
- Python-爬取今日头条美图
- 天才学生的天才回答(爆笑)