Rename
This commit is contained in:
1 parent
b86d90021c
commit
6c0757c91b
972 files changed
+6885
-7321
No files matched your search
@@ -0,0 +1,270 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package io.legato.kazusa.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Bitmap.Config
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import com.google.android.renderscript.Toolkit
|
||||
import java.io.*
|
||||
import kotlin.math.*
|
||||
|
||||
|
||||
@Suppress("WeakerAccess", "MemberVisibilityCanBePrivate")
|
||||
object BitmapUtils {
|
||||
|
||||
/**
|
||||
* 从path中获取图片信息,在通过BitmapFactory.decodeFile(String path)方法将突破转成Bitmap时,
|
||||
* 遇到大一些的图片,我们经常会遇到OOM(Out Of Memory)的问题。所以用到了我们上面提到的BitmapFactory.Options这个类。
|
||||
*
|
||||
* @param path 文件路径
|
||||
* @param width 想要显示的图片的宽度
|
||||
* @param height 想要显示的图片的高度
|
||||
* @return
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun decodeBitmap(path: String, width: Int, height: Int? = null): Bitmap? {
|
||||
val fis = FileInputStream(path)
|
||||
return fis.use {
|
||||
val op = BitmapFactory.Options()
|
||||
// inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight;
|
||||
op.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeFileDescriptor(fis.fd, null, op)
|
||||
op.inSampleSize = calculateInSampleSize(op, width, height)
|
||||
op.inJustDecodeBounds = false
|
||||
BitmapFactory.decodeFileDescriptor(fis.fd, null, op)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*计算 InSampleSize。缺省返回1
|
||||
* @param options BitmapFactory.Options,
|
||||
* @param width 想要显示的图片的宽度
|
||||
* @param height 想要显示的图片的高度
|
||||
* @return
|
||||
*/
|
||||
private fun calculateInSampleSize(
|
||||
options: BitmapFactory.Options,
|
||||
width: Int? = null,
|
||||
height: Int? = null
|
||||
): Int {
|
||||
//获取比例大小
|
||||
val wRatio = width?.let { options.outWidth / it } ?: -1
|
||||
val hRatio = height?.let { options.outHeight / it } ?: -1
|
||||
//如果超出指定大小,则缩小相应的比例
|
||||
return when {
|
||||
wRatio > 1 && hRatio > 1 -> max(wRatio, hRatio)
|
||||
wRatio > 1 -> wRatio
|
||||
hRatio > 1 -> hRatio
|
||||
else -> 1
|
||||
}
|
||||
}
|
||||
|
||||
/** 从path中获取Bitmap图片
|
||||
* @param path 图片路径
|
||||
* @return
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun decodeBitmap(path: String): Bitmap? {
|
||||
val fis = FileInputStream(path)
|
||||
return fis.use {
|
||||
val opts = BitmapFactory.Options()
|
||||
opts.inJustDecodeBounds = true
|
||||
|
||||
BitmapFactory.decodeFileDescriptor(fis.fd, null, opts)
|
||||
opts.inSampleSize = computeSampleSize(opts, -1, 128 * 128)
|
||||
opts.inJustDecodeBounds = false
|
||||
BitmapFactory.decodeFileDescriptor(fis.fd, null, opts)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 以最省内存的方式读取本地资源的图片
|
||||
* @param context 设备上下文
|
||||
* @param resId 资源ID
|
||||
* @return
|
||||
*/
|
||||
fun decodeBitmap(context: Context, resId: Int): Bitmap? {
|
||||
val opt = BitmapFactory.Options()
|
||||
opt.inPreferredConfig = Config.RGB_565
|
||||
return BitmapFactory.decodeResource(context.resources, resId, opt)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context 设备上下文
|
||||
* @param resId 资源ID
|
||||
* @param width
|
||||
* @param height
|
||||
* @return
|
||||
*/
|
||||
fun decodeBitmap(context: Context, resId: Int, width: Int, height: Int): Bitmap? {
|
||||
val op = BitmapFactory.Options()
|
||||
// inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight;
|
||||
op.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeResource(context.resources, resId, op) //获取尺寸信息
|
||||
op.inSampleSize = calculateInSampleSize(op, width, height)
|
||||
op.inJustDecodeBounds = false
|
||||
return BitmapFactory.decodeResource(context.resources, resId, op)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context 设备上下文
|
||||
* @param fileNameInAssets Assets里面文件的名称
|
||||
* @param width 图片的宽度
|
||||
* @param height 图片的高度
|
||||
* @return Bitmap
|
||||
* @throws IOException
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun decodeAssetsBitmap(
|
||||
context: Context,
|
||||
fileNameInAssets: String,
|
||||
width: Int,
|
||||
height: Int
|
||||
): Bitmap? {
|
||||
var inputStream = context.assets.open(fileNameInAssets)
|
||||
return inputStream.use {
|
||||
val op = BitmapFactory.Options()
|
||||
// inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight;
|
||||
op.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeStream(inputStream, null, op) //获取尺寸信息
|
||||
op.inSampleSize = calculateInSampleSize(op, width, height)
|
||||
inputStream = context.assets.open(fileNameInAssets)
|
||||
op.inJustDecodeBounds = false
|
||||
BitmapFactory.decodeStream(inputStream, null, op)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param options
|
||||
* @param minSideLength
|
||||
* @param maxNumOfPixels
|
||||
* @return
|
||||
* 设置恰当的inSampleSize是解决该问题的关键之一。BitmapFactory.Options提供了另一个成员inJustDecodeBounds。
|
||||
* 设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。
|
||||
* 有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。
|
||||
* 查看Android源码,Android提供了下面这种动态计算的方法。
|
||||
*/
|
||||
fun computeSampleSize(
|
||||
options: BitmapFactory.Options,
|
||||
minSideLength: Int,
|
||||
maxNumOfPixels: Int
|
||||
): Int {
|
||||
val initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels)
|
||||
var roundedSize: Int
|
||||
if (initialSize <= 8) {
|
||||
roundedSize = 1
|
||||
while (roundedSize < initialSize) {
|
||||
roundedSize = roundedSize shl 1
|
||||
}
|
||||
} else {
|
||||
roundedSize = (initialSize + 7) / 8 * 8
|
||||
}
|
||||
return roundedSize
|
||||
}
|
||||
|
||||
|
||||
private fun computeInitialSampleSize(
|
||||
options: BitmapFactory.Options,
|
||||
minSideLength: Int,
|
||||
maxNumOfPixels: Int
|
||||
): Int {
|
||||
|
||||
val w = options.outWidth.toDouble()
|
||||
val h = options.outHeight.toDouble()
|
||||
|
||||
val lowerBound = when (maxNumOfPixels) {
|
||||
-1 -> 1
|
||||
else -> ceil(sqrt(w * h / maxNumOfPixels)).toInt()
|
||||
}
|
||||
|
||||
val upperBound = when (minSideLength) {
|
||||
-1 -> 128
|
||||
else -> min(
|
||||
floor(w / minSideLength),
|
||||
floor(h / minSideLength)
|
||||
).toInt()
|
||||
}
|
||||
|
||||
if (upperBound < lowerBound) {
|
||||
// return the larger one when there is no overlapping zone.
|
||||
return lowerBound
|
||||
}
|
||||
|
||||
return when {
|
||||
maxNumOfPixels == -1 && minSideLength == -1 -> {
|
||||
1
|
||||
}
|
||||
minSideLength == -1 -> {
|
||||
lowerBound
|
||||
}
|
||||
else -> {
|
||||
upperBound
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Bitmap转换成InputStream
|
||||
*
|
||||
* @param bitmap
|
||||
* @return
|
||||
*/
|
||||
fun toInputStream(bitmap: Bitmap): InputStream {
|
||||
val bos = ByteArrayOutputStream()
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 90 /*ignored for PNG*/, bos)
|
||||
return ByteArrayInputStream(bos.toByteArray()).also { bos.close() }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定宽高的图片
|
||||
*/
|
||||
fun Bitmap.resizeAndRecycle(newWidth: Int, newHeight: Int): Bitmap {
|
||||
//获取新的bitmap
|
||||
val bitmap = Toolkit.resize(this, newWidth, newHeight)
|
||||
recycle()
|
||||
return bitmap
|
||||
}
|
||||
|
||||
/**
|
||||
* 高斯模糊
|
||||
*/
|
||||
fun Bitmap.stackBlur(radius: Int = 8): Bitmap {
|
||||
return Toolkit.blur(this, radius)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取平均色
|
||||
*/
|
||||
fun Bitmap.getMeanColor(): Int {
|
||||
val width: Int = this.width
|
||||
val height: Int = this.height
|
||||
var pixel: Int
|
||||
var pixelSumRed = 0
|
||||
var pixelSumBlue = 0
|
||||
var pixelSumGreen = 0
|
||||
for (i in 0..99) {
|
||||
for (j in 70..99) {
|
||||
pixel = this.getPixel(
|
||||
(i * width / 100.toFloat()).roundToInt(),
|
||||
(j * height / 100.toFloat()).roundToInt()
|
||||
)
|
||||
pixelSumRed += Color.red(pixel)
|
||||
pixelSumGreen += Color.green(pixel)
|
||||
pixelSumBlue += Color.blue(pixel)
|
||||
}
|
||||
}
|
||||
val averagePixelRed = pixelSumRed / 3000
|
||||
val averagePixelBlue = pixelSumBlue / 3000
|
||||
val averagePixelGreen = pixelSumGreen / 3000
|
||||
return Color.rgb(
|
||||
averagePixelRed + 3,
|
||||
averagePixelGreen + 3,
|
||||
averagePixelBlue + 3
|
||||
)
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user