方法列表
id2Bitmap :获取资源图片的 Bitmap
string2Bitmap :string -> bitmap 通过 Base64 实现
bitmap2String :bitmap -> string 通过 Base64实现
bytes2Bitmap :把byte字节流转成bitmap
bitmap2Bytes :把bitmap转成byte字节流
drawable2Bitmap :drawable 转 bitmap
drawable2Bitmap2:drawable 转 bitmap
bitmap2Drawable :bitmap -> drawable
word2Bitmap :根据文字获取图片
bitmap2Round :获取圆角图片
bitmap2Semicircle:bitmap -> semicircle(半圆)
uri2Bitmap :uri -> bitmap
view2Bitmap2 :通过 View 获取 bitmap,view绘制出来后才行
view2Bitmap :单个View 参数,绘制已经测量过的View,已经显示在界面上,要等控件可以获取到宽高后才行
view2Bitmap :先测量和布局,再生成Bitmap, 没有显示在界面上,针对不可见 View,可以 View 也可以使用
zoomImage :图片的缩放方法,尺寸压缩
compressPathSize:压缩文件读取图片的尺寸大小
compressBitmap :质量压缩方法
compressPathFileSize:压缩图片的内存大小,使文件占据更小的空间
saveFile :保存Bitmap图片为本地文件
完整代码
object BitmapUtils {
/**
* 获取资源图片的 Bitmap
*/
fun id2Bitmap(resId: Int): Bitmap? {
var bitmap: Bitmap? = null
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
val vectorDrawable: Drawable = getContext().getDrawable(resId) ?: return bitmap
bitmap = Bitmap.createBitmap(
vectorDrawable.intrinsicWidth,
vectorDrawable.intrinsicHeight, Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap!!)
vectorDrawable.setBounds(0, 0, canvas.width, canvas.height)
vectorDrawable.draw(canvas)
} else {
bitmap = BitmapFactory.decodeResource(getResources(), resId)
}
return bitmap
}
/**
* string -> bitmap 通过 Base64 实现
*
* @param string
* @return
*/
fun string2Bitmap(string: String?): Bitmap? {
// 将字符串转换成Bitmap类型
var bitmap: Bitmap? = null
try {
val bitmapArray: ByteArray = Base64.decode(string, Base64.DEFAULT)
bitmap = BitmapFactory.decodeByteArray(
bitmapArray, 0,
bitmapArray.size
)
} catch (e: Exception) {
e.printStackTrace()
}
return bitmap
}
/**
* bitmap -> string 通过 Base64实现
*
* @param bitmap
* @return
*/
fun bitmap2String(bitmap: Bitmap): String? {
//将Bitmap转换成字符串
var string: String? = null
val bStream = ByteArrayOutputStream()
bitmap.compress(CompressFormat.PNG, 100, bStream)
val bytes = bStream.toByteArray()
string = Base64.encodeToString(bytes, Base64.DEFAULT)
return string
}
/**
* 把byte字节流转成bitmap
* @param bytes
*/
fun bytes2Bitmap(bytes: ByteArray): Bitmap? {
val opts = BitmapFactory.Options()
opts.inJustDecodeBounds = false //为true时,返回的bitmap为null
return BitmapFactory.decodeByteArray(bytes, 0, bytes.size, opts)
}
/**
* 把bitmap转成byte字节流
* @param bm
*/
fun bitmap2Bytes(bm: Bitmap): ByteArray {
val baos = ByteArrayOutputStream()
bm.compress(Bitmap.CompressFormat.PNG, 100, baos)
return baos.toByteArray()
}
/**
* drawable 转 bitmap
*
* @param drawable
* @return
*/
fun drawable2Bitmap(drawable: Drawable): Bitmap {
val bd = drawable as BitmapDrawable
return bd.bitmap
}
/**
* drawable 转 bitmap
*
* @param drawable
* @return
*/
fun drawable2Bitmap2(drawable: Drawable): Bitmap {
// 取 drawable 的长宽
val w = drawable.intrinsicWidth
val h = drawable.intrinsicHeight
// 取 drawable 的颜色格式
val config =
if (drawable.opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
// 建立对应 bitmap
val bitmap = Bitmap.createBitmap(w, h, config)
// 建立对应 bitmap 的画布
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, w, h)
// 把 drawable 内容画到画布中
drawable.draw(canvas)
return bitmap
}
/**
* bitmap -> drawable
*
* @param bitmap
* @return
*/
fun bitmap2Drawable(bitmap: Bitmap): Drawable {
val drawable: Drawable = BitmapDrawable(bitmap)
drawable.setBounds(0, 0, bitmap.width, bitmap.height)
return drawable
}
/**
* 根据文字获取图片
*
* @param text
* @return
*/
fun word2Bitmap(context: Context, text: String?, drawableId: Int): Bitmap {
val color = "#ffeeeade"
val src = BitmapFactory.decodeResource(
context.getResources(),
drawableId
)
val x = src.width
val y = src.height
val bmp = Bitmap.createBitmap(x, y, Bitmap.Config.ARGB_8888)
val canvasTemp = Canvas(bmp)
canvasTemp.drawColor(Color.parseColor(color))
val p = Paint(Paint.FAKE_BOLD_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG)
p.color = Color.parseColor("#ff4e0a13")
p.alpha = 45
p.isFilterBitmap = true
val size = (18 * context.resources.displayMetrics.density)
p.textSize = size
val tX: Float = (x - getFontlength(p, text)) / 2
val tY: Float = (y - getFontHeight(p)) / 2 + getFontLeading(p)
canvasTemp.drawText(text!!, tX, tY, p)
return bmp
}
/**
* @return 返回指定笔和指定字符串的长度
*/
fun getFontlength(paint: Paint, str: String?): Float {
return paint.measureText(str)
}
/**
* @return 返回指定笔的文字高度
*/
fun getFontHeight(paint: Paint): Float {
val fm = paint.fontMetrics
return fm.descent - fm.ascent
}
/**
* @return 返回指定笔离文字顶部的基准距离
*/
fun getFontLeading(paint: Paint): Float {
val fm = paint.fontMetrics
return fm.leading - fm.ascent
}
/**
* 获取圆角图片
*
* @param bitmap
* @param pixels
* @return
*/
fun bitmap2Round(bitmap: Bitmap, pixels: Float): Bitmap {
val output = Bitmap.createBitmap(
bitmap.width,
bitmap.height, Bitmap.Config.ARGB_8888
)
val canvas = Canvas(output)
val color = -0xbdbdbe
val paint = Paint()
val rect = Rect(0, 0, bitmap.width, bitmap.height)
val rectF = RectF(rect)
paint.isAntiAlias = true
canvas.drawARGB(0, 0, 0, 0)
paint.color = color
canvas.drawRoundRect(rectF, pixels, pixels, paint)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(bitmap, rect, rect, paint)
return output
}
/**
* bitmap -> semicircle(半圆)
*
* @param bitmap
* @return
*/
fun bitmap2Semicircle(bitmap: Bitmap): Bitmap? {
val output = Bitmap.createBitmap(
bitmap.width, bitmap
.height, Bitmap.Config.ARGB_8888
)
val canvas = Canvas(output)
val color = -0xbdbdbe
val paint = Paint()
val rect = Rect(0, 0, bitmap.width, bitmap.height)
val rectF = RectF(rect)
paint.isAntiAlias = true
canvas.drawARGB(0, 0, 0, 0)
paint.color = color
canvas.drawOval(rectF, paint)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(bitmap, rect, rect, paint)
return output
}
/**
* uri -> bitmap
*
* @param context
* @param uri
* @return
*/
fun uri2Bitmap(context: Context, uri: Uri?): Bitmap? {
var bp: Bitmap? = null
bp = try {
BitmapFactory.decodeStream(
uri?.let {
context.contentResolver
.openInputStream(it)
}
)
//CompressPic.compressBitmap(bitmap, 400, 400)
} catch (e: FileNotFoundException) {
e.printStackTrace()
return null
}
return bp
}
/***
* 图片的缩放方法
*
* @param bitmap :源图片资源
* @param newWidth:缩放后宽度
* @param newHeight 缩放后高度
* @return
*/
fun zoomImage(bitmap: Bitmap, newWidth: Double, newHeight: Double): Bitmap {
// 获取这个图片的宽和高
val width = bitmap.width.toFloat()
val height = bitmap.height.toFloat()
// 创建操作图片用的matrix对象
val matrix = Matrix()
// 计算宽高缩放率
val scaleWidth = newWidth.toFloat() / width
val scaleHeight = newHeight.toFloat() / height
// 缩放图片动作
matrix.postScale(scaleWidth, scaleHeight)
return Bitmap.createBitmap(
bitmap, 0, 0, width.toInt(),
height.toInt(), matrix, true
)
}
fun zoomBitmap(bitmap: Bitmap, scale: Float): Bitmap {
return zoomBitmap(bitmap, scale, scale)
}
/**
* 图片的缩放方法
*
* @param bitmap
* @param scaleWidth
* @param scaleHeight
* @return
*/
fun zoomBitmap(bitmap: Bitmap, scaleWidth: Float, scaleHeight: Float): Bitmap {
// 获取这个图片的宽和高
val width = bitmap.width.toFloat()
val height = bitmap.height.toFloat()
// 创建操作图片用的matrix对象
val matrix = Matrix()
// 缩放图片动作
matrix.postScale(scaleWidth, scaleHeight)
return Bitmap.createBitmap(
bitmap, 0, 0, width.toInt(),
height.toInt(), matrix, true
)
}
/**
* 压缩图片的尺寸大小
*
* @param path
* @param newWidth
* @param newHight
* @return
*/
fun compressPathSize(path: String?, newWidth: Int, newHight: Int): Bitmap {
//先获取图片的尺寸大小
//获取解析bitmap的选项参数
val options = BitmapFactory.Options()
//仅仅解析图片的边框
options.inJustDecodeBounds = true
//从路径或文件中获取图片bitmap对象
val bitmap = BitmapFactory.decodeFile(path, options)
//解析后,bitmap为空,会将长度和宽度放到options中,
//此时取得bitmap的宽高
val oldWidth = Math.ceil(options.outWidth.toDouble()).toInt() //向上取整
val oldHight = Math.ceil(options.outHeight.toDouble()).toInt()
//获取宽高的比例
val sizeWidth = oldWidth / newWidth
val sizeHight = oldHight / newHight
val sampleSize = if (sizeHight > sizeWidth) sizeHight else sizeWidth
//如果超出指定的大小,就压缩图片
if (sizeHight > 1 && sizeWidth > 1) {
//如同前面的步骤,向选项参数中放入新的压缩比例
options.inSampleSize = sampleSize
}
//需要完整解析整张图片
options.inJustDecodeBounds = false
//按照新的缩放比例重新解析
return BitmapFactory.decodeFile(path, options)
}
/**
* 质量压缩方法
*
* @param image
* @return
*/
fun compressBitmap(image: Bitmap): Bitmap? {
val baos = ByteArrayOutputStream()
image.compress(Bitmap.CompressFormat.JPEG, 100, baos) //质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
var options = 90
var bytes: Int = baos.toByteArray().size
while (bytes / 1024 > 100 && options >= 20) { //循环判断如果压缩后图片是否大于10kb,大于继续压缩
baos.reset() //重置baos即清空baos
options -= 10 //每次都减少10
//第一个参数 :图片格式 ,第二个参数: 图片质量,100为最高,0为最差 ,第三个参数:保存压缩后的数据的流
image.compress(Bitmap.CompressFormat.JPEG, options, baos) //这里压缩options%,把压缩后的数据存放到baos中
bytes = baos.toByteArray().size
}
image.recycle()
val isBm = ByteArrayInputStream(baos.toByteArray()) //把压缩后的数据baos存放到ByteArrayInputStream中
return BitmapFactory.decodeStream(isBm, null, null) //把ByteArrayInputStream数据生成图片
}
/**
* 压缩图片的内存大小,使文件占据更小的空间
*
* @param path
* @param newFileName
* @param size
* @return
*/
fun compressPathFileSize(path: String, newFileName: String, size: Int): String { //size单位kb
//先获取图片bitmap
val bitmap = BitmapFactory.decodeFile(path)
//将图片压缩到想要的内存以内
//第一次,不压缩图片,先判断图片内存是否符合要求
val baos = ByteArrayOutputStream()
var compressQuality = 100
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
while (baos.toByteArray().size / 1024 > size) {
//清空已经写入的流
baos.reset()
//大于想要的尺寸继续压缩
compressQuality -= 10
bitmap.compress(Bitmap.CompressFormat.JPEG, compressQuality, baos)
}
//跳出循环,表示图片尺寸已经小于size,往文件中写
var fos: FileOutputStream? = null
try {
fos = FileOutputStream(File(path, "$newFileName.jpg"))
val bytes = baos.toByteArray()
fos.write(bytes, 0, bytes.size)
fos.flush()
return path.replace(".jpg", "$newFileName.jpg")
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
baos.close()
} catch (e: IOException) {
e.printStackTrace()
}
if (fos != null) {
try {
fos.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
return path
}
/**
* 保存Bitmap图片为本地文件
*/
fun saveFile(bitmap: Bitmap, filename: String?) {
var fileOutputStream: FileOutputStream? = null
try {
fileOutputStream = FileOutputStream(filename)
bitmap.compress(CompressFormat.PNG, 90, fileOutputStream)
fileOutputStream.flush()
fileOutputStream.close()
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
/**
* 通过 View 获取 bitmap,view绘制出来后才行
*
* @param v
* @return
*/
fun view2Bitmap2(v: View): Bitmap? {
v.clearFocus() //
v.isPressed = false //
// 能画缓存就返回false
val willNotCache: Boolean = v.willNotCacheDrawing()
v.setWillNotCacheDrawing(false)
val color: Int = v.drawingCacheBackgroundColor
v.drawingCacheBackgroundColor = 0
if (color != 0) {
v.destroyDrawingCache()
}
v.buildDrawingCache()
val cacheBitmap: Bitmap = v.drawingCache ?: return null
val bitmap = Bitmap.createBitmap(cacheBitmap)
// Restore the view
v.destroyDrawingCache()
v.setWillNotCacheDrawing(willNotCache)
v.drawingCacheBackgroundColor = color
return bitmap
}
/**
* 绘制已经测量过的View,已经显示在界面上,要等控件可以获取到宽高后才行
*/
fun view2Bitmap(view: View): Bitmap? {
val width = view.width
val height = view.height
if (width <= 0 || height <= 0) return null
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
val canvas = Canvas(bitmap)
view.draw(canvas)
return bitmap
}
/**
* 先测量和布局,再生成Bitmap, 没有显示在界面上,针对不可见 View,可以 View 也可以使用
*/
fun view2Bitmap(view: View, context: Activity): Bitmap? {
val metric = DisplayMetrics()
context.windowManager.defaultDisplay.getMetrics(metric)
val screenWidth = metric.widthPixels // 屏幕宽度(像素)
val screenHeight = metric.heightPixels // 屏幕高度(像素)
// 测量
val widthSpec = View.MeasureSpec.makeMeasureSpec(screenWidth, View.MeasureSpec.AT_MOST)
val heightSpec = View.MeasureSpec.makeMeasureSpec(screenHeight, View.MeasureSpec.AT_MOST)
view.measure(widthSpec, heightSpec)
// 布局
val measuredWidth = view.measuredWidth
val measuredHeight = view.measuredHeight
view.layout(0, 0, measuredWidth, measuredHeight)
// 绘制
val width = view.width
val height = view.height
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
//canvas.drawColor(ResUtils.INSTANCE.getColor(R.color.black_5));
view.draw(canvas)
return bitmap
}
}