1+ import android.graphics.Bitmap
2+ import android.graphics.Color
3+ import android.graphics.ColorMatrix
4+ import android.graphics.ColorMatrixColorFilter
5+ import android.graphics.Paint
6+ import android.media.ThumbnailUtils
7+ import androidx.compose.ui.graphics.toArgb
8+
9+
10+ /* *
11+ * 位图灰度
12+ */
13+ fun Bitmap.toGrayscale (): Bitmap {
14+ val bmpGrayscale = Bitmap .createBitmap(width, height, Bitmap .Config .ARGB_8888 )
15+ val c = android.graphics.Canvas (bmpGrayscale)
16+ val paint = Paint ()
17+ val cm = ColorMatrix ()
18+ cm.setSaturation(0f )
19+ val f = ColorMatrixColorFilter (cm)
20+ paint.colorFilter = f
21+ c.drawBitmap(this , 0f , 0f , paint)
22+ return bmpGrayscale
23+ }
24+
25+
26+ /* *
27+ * 位图单色化
28+ */
29+ fun Bitmap.toColor (color : androidx.compose.ui.graphics.Color ): Bitmap {
30+ val bmp = Bitmap .createBitmap(
31+ width, height, Bitmap .Config .ARGB_8888
32+ )
33+ val oldPx = IntArray (width * height) // 用来存储原图每个像素点的颜色信息
34+ getPixels(oldPx, 0 , width, 0 , 0 , width, height) // 获取原图中的像素信息
35+
36+ val newPx = oldPx.map {
37+ color.copy(Color .alpha(it) / 255f ).toArgb()
38+ }.toTypedArray().toIntArray()
39+ bmp.setPixels(newPx, 0 , width, 0 , 0 , width, height) // 将处理后的像素信息赋给新图
40+ return bmp
41+ }
42+
43+
44+ /* *
45+ * 转为二值图像
46+ *
47+ * @param bmp 原图bitmap
48+ *
49+ * @return
50+ */
51+ fun Bitmap.convertToBMW (tmp : Int = 100): Bitmap {
52+ val pixels = IntArray (width * height) // 通过位图的大小创建像素点数组
53+ // 设定二值化的域值,默认值为100
54+ // tmp = 180;
55+ getPixels(pixels, 0 , width, 0 , 0 , width, height)
56+ var alpha = 0xFF shl 24
57+ for (i in 0 until height) {
58+ for (j in 0 until width) {
59+ val grey = pixels[width * i + j]
60+ // 分离三原色
61+ alpha = grey and - 0x1000000 shr 24
62+ var red = grey and 0x00FF0000 shr 16
63+ var green = grey and 0x0000FF00 shr 8
64+ var blue = grey and 0x000000FF
65+ if (red > tmp) {
66+ red = 255
67+ } else {
68+ red = 0
69+ }
70+ if (blue > tmp) {
71+ blue = 255
72+ } else {
73+ blue = 0
74+ }
75+ if (green > tmp) {
76+ green = 255
77+ } else {
78+ green = 0
79+ }
80+ pixels[width * i + j] = (alpha shl 24 or (red shl 16 ) or (green shl 8 )
81+ or blue)
82+ if (pixels[width * i + j] == - 1 ) {
83+ pixels[width * i + j] = - 1
84+ } else {
85+ pixels[width * i + j] = - 16777216
86+ }
87+ }
88+ }
89+ // 新建图片
90+ val newBmp = Bitmap .createBitmap(width, height, Bitmap .Config .ARGB_8888 )
91+ // 设置图片数据
92+ newBmp.setPixels(pixels, 0 , width, 0 , 0 , width, height)
93+ val bitmap = ThumbnailUtils .extractThumbnail(newBmp, width, height)
94+ return bitmap
95+ }
96+
97+
98+ // 抖动算法来对图像进行二值化处理
99+ fun Bitmap.convertGreyImgByFloyd (): Bitmap {
100+ val pixels = IntArray (width * height) // 通过位图的大小创建像素点数组
101+ getPixels(pixels, 0 , width, 0 , 0 , width, height)
102+ val gray = IntArray (height * width)
103+ for (i in 0 until height) {
104+ for (j in 0 until width) {
105+ val grey = pixels[width * i + j]
106+ val red = grey and 0x00FF0000 shr 16
107+ gray[width * i + j] = red
108+ }
109+ }
110+ var e = 0
111+ for (i in 0 until height) {
112+ for (j in 0 until width) {
113+ val g = gray[width * i + j]
114+ if (g >= 128 ) {
115+ pixels[width * i + j] = (Color .alpha(pixels[width * i + j]) shl 24 ) or - 0x1
116+ e = g - 255
117+
118+ } else {
119+ pixels[width * i + j] = - 0x1000000
120+ e = g - 0
121+ }
122+ if (j < width - 1 && i < height - 1 ) {
123+ // 右边像素处理
124+ gray[width * i + j + 1 ] + = 3 * e / 8
125+ // 下
126+ gray[width * (i + 1 ) + j] + = 3 * e / 8
127+ // 右下
128+ gray[width * (i + 1 ) + j + 1 ] + = e / 4
129+ } else if (j == width - 1 && i < height - 1 ) {// 靠右或靠下边的像素的情况
130+ // 下方像素处理
131+ gray[width * (i + 1 ) + j] + = 3 * e / 8
132+ } else if (j < width - 1 && i == height - 1 ) {
133+ // 右边像素处理
134+ gray[width * i + j + 1 ] + = e / 4
135+ }
136+ }
137+ }
138+ val mBitmap = Bitmap .createBitmap(width, height, Bitmap .Config .ARGB_8888 )
139+ mBitmap.setPixels(pixels, 0 , width, 0 , 0 , width, height)
140+ return mBitmap
141+ }
142+
143+
144+ /* *
145+ * 图片进行二值化黑白
146+ */
147+ fun zeroAndOne (bm : Bitmap ): Bitmap ? {
148+ val width = bm.width // 原图像宽度
149+ val height = bm.height // 原图像高度
150+ var color: Int // 用来存储某个像素点的颜色值
151+ var r: Int
152+ var g: Int
153+ var b: Int
154+ var a: Int // 红,绿,蓝,透明度
155+ // 创建空白图像,宽度等于原图宽度,高度等于原图高度,用ARGB_8888渲染,这个不用了解,这样写就行了
156+ val bmp = Bitmap .createBitmap(
157+ width, height, Bitmap .Config .ARGB_8888
158+ )
159+ val oldPx = IntArray (width * height) // 用来存储原图每个像素点的颜色信息
160+ val newPx = IntArray (width * height) // 用来处理处理之后的每个像素点的颜色信息
161+ /* *
162+ * 第一个参数oldPix[]:用来接收(存储)bm这个图像中像素点颜色信息的数组
163+ * 第二个参数offset:oldPix[]数组中第一个接收颜色信息的下标值
164+ * 第三个参数width:在行之间跳过像素的条目数,必须大于等于图像每行的像素数
165+ * 第四个参数x:从图像bm中读取的第一个像素的横坐标
166+ * 第五个参数y:从图像bm中读取的第一个像素的纵坐标
167+ * 第六个参数width:每行需要读取的像素个数
168+ * 第七个参数height:需要读取的行总数
169+ */
170+ bm.getPixels(oldPx, 0 , width, 0 , 0 , width, height) // 获取原图中的像素信息
171+ for (i in 0 until width * height) { // 循环处理图像中每个像素点的颜色值
172+ color = oldPx[i] // 取得某个点的像素值
173+ r = Color .red(color) // 取得此像素点的r(红色)分量
174+ g = Color .green(color) // 取得此像素点的g(绿色)分量
175+ b = Color .blue(color) // 取得此像素点的b(蓝色分量)
176+ a = Color .alpha(color) // 取得此像素点的a通道值
177+
178+ // 此公式将r,g,b运算获得灰度值,经验公式不需要理解
179+ var gray = (r.toFloat() * 0.3 + g.toFloat() * 0.59 + b.toFloat() * 0.11 ).toInt()
180+ // 下面前两个if用来做溢出处理,防止灰度公式得到到灰度超出范围(0-255)
181+ if (gray > 255 ) {
182+ gray = 255
183+ }
184+ if (gray < 0 ) {
185+ gray = 0
186+ }
187+ if (gray != 0 ) { // 如果某像素的灰度值不是0(黑色)就将其置为255(白色)
188+ gray = 255
189+ }
190+ newPx[i] = Color .argb(a, gray, gray, gray) // 将处理后的透明度(没变),r,g,b分量重新合成颜色值并将其存储在数组中
191+ }
192+ /* *
193+ * 第一个参数newPix[]:需要赋给新图像的颜色数组//The colors to write the bitmap
194+ * 第二个参数offset:newPix[]数组中第一个需要设置给图像颜色的下标值//The index of the first color to read from pixels[]
195+ * 第三个参数width:在行之间跳过像素的条目数//The number of colors in pixels[] to skip between rows.
196+ * Normally this value will be the same as the width of the bitmap,but it can be larger(or negative).
197+ * 第四个参数x:从图像bm中读取的第一个像素的横坐标//The x coordinate of the first pixels to write to in the bitmap.
198+ * 第五个参数y:从图像bm中读取的第一个像素的纵坐标//The y coordinate of the first pixels to write to in the bitmap.
199+ * 第六个参数width:每行需要读取的像素个数The number of colors to copy from pixels[] per row.
200+ * 第七个参数height:需要读取的行总数//The number of rows to write to the bitmap.
201+ */
202+ bmp.setPixels(newPx, 0 , width, 0 , 0 , width, height) // 将处理后的像素信息赋给新图
203+ return bmp // 返回处理后的图像
204+ }
205+
206+
207+ fun gray2Binary (graymap : Bitmap ): Bitmap ? {
208+ // 得到图形的宽度和长度
209+ val width = graymap.width
210+ val height = graymap.height
211+ // 创建二值化图像
212+ var binarymap: Bitmap ? = null
213+ binarymap = graymap.copy(Bitmap .Config .ARGB_8888 , true )
214+ // 依次循环,对图像的像素进行处理
215+ for (i in 0 until width) {
216+ for (j in 0 until height) {
217+ // 得到当前像素的值
218+ val col = binarymap.getPixel(i, j)
219+ // 得到alpha通道的值
220+ val alpha = col and - 0x1000000
221+ // 得到图像的像素RGB的值
222+ val red = col and 0x00FF0000 shr 16
223+ val green = col and 0x0000FF00 shr 8
224+ val blue = col and 0x000000FF
225+ // 用公式X = 0.3×R+0.59×G+0.11×B计算出X代替原来的RGB
226+ var gray =
227+ (red.toFloat() * 0.3 + green.toFloat() * 0.59 + blue.toFloat() * 0.11 ).toInt()
228+ // 对图像进行二值化处理
229+ gray = if (gray <= 95 ) {
230+ 0
231+ } else {
232+ 255
233+ }
234+ // 新的ARGB
235+ val newColor = alpha or (gray shl 16 ) or (gray shl 8 ) or gray
236+ // 设置新图像的当前像素值
237+ binarymap.setPixel(i, j, newColor)
238+ }
239+ }
240+ return binarymap
241+ }
0 commit comments