pull/36/head
kunfei 5 years ago
parent b2ac302c45
commit bced8f3837
  1. 37
      app/src/main/java/io/legado/app/help/ReadBookConfig.kt
  2. 2
      app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt
  3. 6
      app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt
  4. 252
      app/src/main/java/io/legado/app/utils/BitmapUtil.kt

@ -1,6 +1,7 @@
package io.legado.app.help package io.legado.app.help
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import io.legado.app.App import io.legado.app.App
@ -52,7 +53,11 @@ object ReadBookConfig {
} }
fun upBg() { fun upBg() {
bg = getConfig().bgDrawable() val resources = App.INSTANCE.resources
val dm = resources.displayMetrics
val width = dm.widthPixels
val height = dm.heightPixels
bg = getConfig().bgDrawable(width, height)
} }
fun save() { fun save() {
@ -162,20 +167,30 @@ object ReadBookConfig {
else bgType else bgType
} }
fun bgDrawable(): Drawable { fun bgDrawable(width: Int, height: Int): Drawable {
var bgDrawable: Drawable? = null var bgDrawable: Drawable? = null
kotlin.runCatching { val resources = App.INSTANCE.resources
when (bgType()) { try {
0 -> bgDrawable = ColorDrawable(Color.parseColor(bgStr())) bgDrawable = when (bgType()) {
1 -> bgDrawable = 0 -> ColorDrawable(Color.parseColor(bgStr()))
Drawable.createFromStream( 1 -> {
App.INSTANCE.assets.open("bg" + File.separator + bgStr()), BitmapDrawable(
"bg" resources,
BitmapUtil.decodeBitmap(
App.INSTANCE,
"bg" + File.separator + bgStr(),
width,
height
)
) )
else -> runCatching {
bgDrawable = Drawable.createFromPath(bgStr())
} }
else -> BitmapDrawable(
resources,
BitmapUtil.decodeBitmap(bgStr(), width, height)
)
} }
} catch (e: Exception) {
e.printStackTrace()
} }
return bgDrawable ?: ColorDrawable(App.INSTANCE.getCompatColor(R.color.background)) return bgDrawable ?: ColorDrawable(App.INSTANCE.getCompatColor(R.color.background))
} }

@ -249,7 +249,7 @@ class ReadStyleDialog : DialogFragment() {
ReadBookConfig.getConfig(i).apply { ReadBookConfig.getConfig(i).apply {
when (bgType()) { when (bgType()) {
2 -> ImageLoader.load(requireContext(), bgStr()).centerCrop().setAsDrawable(iv) 2 -> ImageLoader.load(requireContext(), bgStr()).centerCrop().setAsDrawable(iv)
else -> iv.setImageDrawable(bgDrawable()) else -> iv.setImageDrawable(bgDrawable(100, 150))
} }
} }
} }

@ -10,7 +10,6 @@ import android.widget.ImageView
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.AppConst.TIME_FORMAT import io.legado.app.constant.AppConst.TIME_FORMAT
import io.legado.app.help.ImageLoader
import io.legado.app.help.ReadBookConfig import io.legado.app.help.ReadBookConfig
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.android.synthetic.main.view_book_page.view.* import kotlinx.android.synthetic.main.view_book_page.view.*
@ -90,10 +89,7 @@ class ContentView : FrameLayout {
} }
fun setBg(bg: Drawable?) { fun setBg(bg: Drawable?) {
//all supported bgImage.background = bg
ImageLoader.load(context, bg)
.centerCrop()
.setAsDrawable(bgImage)
} }
fun upTime() { fun upTime() {

@ -0,0 +1,252 @@
package io.legado.app.utils
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.Config
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.renderscript.Allocation
import android.renderscript.Element
import android.renderscript.RenderScript
import android.renderscript.ScriptIntrinsicBlur
import android.view.View
import io.legado.app.App
import java.io.IOException
import kotlin.math.ceil
@SuppressWarnings("unused", "WeakerAccess")
object BitmapUtil {
/**
* 从path中获取图片信息,在通过BitmapFactory.decodeFile(String path)方法将突破转成Bitmap时
* 遇到大一些的图片我们经常会遇到OOM(Out Of Memory)的问题所以用到了我们上面提到的BitmapFactory.Options这个类
*
* @param path 文件路径
* @param width 想要显示的图片的宽度
* @param height 想要显示的图片的高度
* @return
*/
fun decodeBitmap(path: String, width: Int, height: Int): Bitmap {
val op = BitmapFactory.Options()
// inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight;
op.inJustDecodeBounds = true
BitmapFactory.decodeFile(path, op) //获取尺寸信息
//获取比例大小
val wRatio = ceil((op.outWidth / width).toDouble()).toInt()
val hRatio = ceil((op.outHeight / height).toDouble()).toInt()
//如果超出指定大小,则缩小相应的比例
if (wRatio > 1 && hRatio > 1) {
if (wRatio > hRatio) {
op.inSampleSize = wRatio
} else {
op.inSampleSize = hRatio
}
}
op.inJustDecodeBounds = false
return BitmapFactory.decodeFile(path, op)
}
/** 从path中获取Bitmap图片
* @param path 图片路径
* @return
*/
fun decodeBitmap(path: String): Bitmap {
val opts = BitmapFactory.Options()
opts.inJustDecodeBounds = true
BitmapFactory.decodeFile(path, opts)
opts.inSampleSize = computeSampleSize(opts, -1, 128 * 128)
opts.inJustDecodeBounds = false
return BitmapFactory.decodeFile(path, opts)
}
/**
* 以最省内存的方式读取本地资源的图片
* @param context 设备上下文
* @param resId 资源ID
* @return
*/
fun decodeBitmap(context: Context, resId: Int): Bitmap? {
val opt = BitmapFactory.Options()
opt.inPreferredConfig = Config.RGB_565
//获取资源图片
val `is` = context.resources.openRawResource(resId)
return BitmapFactory.decodeStream(`is`, null, opt)
}
/**
* @param context 设备上下文
* @param resId 资源ID
* @param width
* @param height
* @return
*/
fun decodeBitmap(context: Context, resId: Int, width: Int, height: Int): Bitmap? {
var inputStream = context.resources.openRawResource(resId)
val op = BitmapFactory.Options()
// inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight;
op.inJustDecodeBounds = true
BitmapFactory.decodeStream(inputStream, null, op) //获取尺寸信息
//获取比例大小
val wRatio = ceil((op.outWidth / width).toDouble()).toInt()
val hRatio = ceil((op.outHeight / height).toDouble()).toInt()
//如果超出指定大小,则缩小相应的比例
if (wRatio > 1 && hRatio > 1) {
if (wRatio > hRatio) {
op.inSampleSize = wRatio
} else {
op.inSampleSize = hRatio
}
}
inputStream = context.resources.openRawResource(resId)
op.inJustDecodeBounds = false
return BitmapFactory.decodeStream(inputStream, null, op)
}
/**
* @param context 设备上下文
* @param fileNameInAssets Assets里面文件的名称
* @param width 图片的宽度
* @param height 图片的高度
* @return Bitmap
* @throws IOException
*/
@Throws(IOException::class)
fun decodeBitmap(context: Context, fileNameInAssets: String, width: Int, height: Int): Bitmap? {
var inputStream = context.assets.open(fileNameInAssets)
val op = BitmapFactory.Options()
// inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight;
op.inJustDecodeBounds = true
BitmapFactory.decodeStream(inputStream, null, op) //获取尺寸信息
//获取比例大小
val wRatio = ceil((op.outWidth / width).toDouble()).toInt()
val hRatio = ceil((op.outHeight / height).toDouble()).toInt()
//如果超出指定大小,则缩小相应的比例
if (wRatio > 1 && hRatio > 1) {
if (wRatio > hRatio) {
op.inSampleSize = wRatio
} else {
op.inSampleSize = hRatio
}
}
inputStream = context.assets.open(fileNameInAssets)
op.inJustDecodeBounds = false
return BitmapFactory.decodeStream(inputStream, null, op)
}
//图片不被压缩
fun convertViewToBitmap(view: View, bitmapWidth: Int, bitmapHeight: Int): Bitmap {
val bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888)
view.draw(Canvas(bitmap))
return bitmap
}
/**
* @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 = if (maxNumOfPixels == -1)
1
else
Math.ceil(Math.sqrt(w * h / maxNumOfPixels)).toInt()
val upperBound = if (minSideLength == -1) 128 else Math.min(
Math.floor(w / minSideLength),
Math.floor(h / minSideLength)
).toInt()
if (upperBound < lowerBound) {
// return the larger one when there is no overlapping zone.
return lowerBound
}
return if (maxNumOfPixels == -1 && minSideLength == -1) {
1
} else if (minSideLength == -1) {
lowerBound
} else {
upperBound
}
}
/**
* 高斯模糊
*/
fun stackBlur(srcBitmap: Bitmap?): Bitmap? {
if (srcBitmap == null) return null
val rs = RenderScript.create(App.INSTANCE)
val blurredBitmap = srcBitmap.copy(Config.ARGB_8888, true)
//分配用于渲染脚本的内存
val input = Allocation.createFromBitmap(
rs,
blurredBitmap,
Allocation.MipmapControl.MIPMAP_FULL,
Allocation.USAGE_SHARED
)
val output = Allocation.createTyped(rs, input.type)
//加载我们想要使用的特定脚本的实例。
val script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs))
script.setInput(input)
//设置模糊半径
script.setRadius(8f)
//启动 ScriptIntrinsicBlur
script.forEach(output)
//将输出复制到模糊的位图
output.copyTo(blurredBitmap)
return blurredBitmap
}
}
Loading…
Cancel
Save