189 lines
5.1 KiB
Kotlin
189 lines
5.1 KiB
Kotlin
|
package jp.juggler.subwaytooter.util
|
||
|
|
||
|
import android.content.Context
|
||
|
import android.graphics.*
|
||
|
import android.net.Uri
|
||
|
import it.sephiroth.android.library.exif2.ExifInterface
|
||
|
|
||
|
object BitmapUtils {
|
||
|
internal val log = LogCategory("BitmapUtils")
|
||
|
}
|
||
|
fun createResizedBitmap(
|
||
|
context : Context,
|
||
|
uri : Uri,
|
||
|
resizeToArg : Int,
|
||
|
skipIfNoNeedToResizeAndRotate : Boolean =false
|
||
|
) : Bitmap? {
|
||
|
var resize_to = resizeToArg
|
||
|
try {
|
||
|
|
||
|
// EXIF回転情報の取得
|
||
|
val orientation : Int? = context.contentResolver.openInputStream(uri)?.use { inStream ->
|
||
|
val exif = ExifInterface()
|
||
|
exif.readExif(
|
||
|
inStream,
|
||
|
ExifInterface.Options.OPTION_IFD_0 or ExifInterface.Options.OPTION_IFD_1 or ExifInterface.Options.OPTION_IFD_EXIF
|
||
|
)
|
||
|
exif.getTagIntValue(ExifInterface.TAG_ORIENTATION)
|
||
|
}
|
||
|
|
||
|
// 画像のサイズを調べる
|
||
|
val options = BitmapFactory.Options()
|
||
|
options.inJustDecodeBounds = true
|
||
|
options.inScaled = false
|
||
|
options.outWidth = 0
|
||
|
options.outHeight = 0
|
||
|
context.contentResolver.openInputStream(uri)?.use { inStream ->
|
||
|
BitmapFactory.decodeStream(inStream, null, options)
|
||
|
}
|
||
|
var src_width = options.outWidth
|
||
|
var src_height = options.outHeight
|
||
|
if(src_width <= 0 || src_height <= 0) {
|
||
|
showToast(context, false, "could not get image bounds.")
|
||
|
return null
|
||
|
}
|
||
|
|
||
|
// 長辺
|
||
|
val size = if(src_width > src_height) src_width else src_height
|
||
|
|
||
|
// リサイズも回転も必要がない場合
|
||
|
if(skipIfNoNeedToResizeAndRotate
|
||
|
&& (orientation == null || orientation == 1)
|
||
|
&& (resize_to <= 0 || size <= resize_to)) {
|
||
|
BitmapUtils.log.d("createOpener: no need to resize & rotate")
|
||
|
return null
|
||
|
}
|
||
|
|
||
|
|
||
|
if(size > resize_to) {
|
||
|
// 縮小が必要
|
||
|
} else {
|
||
|
// 縮小は不要
|
||
|
resize_to = size
|
||
|
}
|
||
|
|
||
|
// inSampleSizeを計算
|
||
|
var bits = 0
|
||
|
var x = size
|
||
|
while(x > resize_to * 2) {
|
||
|
++ bits
|
||
|
x = x shr 1
|
||
|
}
|
||
|
options.inJustDecodeBounds = false
|
||
|
options.inSampleSize = 1 shl bits
|
||
|
|
||
|
val sourceBitmap : Bitmap? =
|
||
|
context.contentResolver.openInputStream(uri)?.use { inStream ->
|
||
|
BitmapFactory.decodeStream(inStream, null, options)
|
||
|
}
|
||
|
|
||
|
if(sourceBitmap == null) {
|
||
|
showToast(context, false, "could not decode image.")
|
||
|
return null
|
||
|
}
|
||
|
try {
|
||
|
src_width = options.outWidth
|
||
|
src_height = options.outHeight
|
||
|
val scale : Float
|
||
|
var dst_width : Int
|
||
|
var dst_height : Int
|
||
|
if(src_width >= src_height) {
|
||
|
scale = resize_to / src_width.toFloat()
|
||
|
dst_width = resize_to
|
||
|
dst_height = (0.5f + src_height / src_width.toFloat() * resize_to).toInt()
|
||
|
if(dst_height < 1) dst_height = 1
|
||
|
} else {
|
||
|
scale = resize_to / src_height.toFloat()
|
||
|
dst_height = resize_to
|
||
|
dst_width = (0.5f + src_width / src_height.toFloat() * resize_to).toInt()
|
||
|
if(dst_width < 1) dst_width = 1
|
||
|
}
|
||
|
|
||
|
val matrix = Matrix()
|
||
|
matrix.reset()
|
||
|
|
||
|
// 画像の中心が原点に来るようにして
|
||
|
matrix.postTranslate(src_width * - 0.5f, src_height * - 0.5f)
|
||
|
// スケーリング
|
||
|
matrix.postScale(scale, scale)
|
||
|
// 回転情報があれば回転
|
||
|
if(orientation != null) {
|
||
|
val tmp : Int
|
||
|
when(orientation) {
|
||
|
|
||
|
2 -> matrix.postScale(1f, - 1f) // 上下反転
|
||
|
3 -> matrix.postRotate(180f) // 180度回転
|
||
|
4 -> matrix.postScale(- 1f, 1f) // 左右反転
|
||
|
|
||
|
5 -> {
|
||
|
tmp = dst_width
|
||
|
|
||
|
dst_width = dst_height
|
||
|
dst_height = tmp
|
||
|
matrix.postScale(1f, - 1f)
|
||
|
matrix.postRotate(- 90f)
|
||
|
}
|
||
|
|
||
|
6 -> {
|
||
|
tmp = dst_width
|
||
|
|
||
|
dst_width = dst_height
|
||
|
dst_height = tmp
|
||
|
matrix.postRotate(90f)
|
||
|
}
|
||
|
|
||
|
7 -> {
|
||
|
tmp = dst_width
|
||
|
|
||
|
dst_width = dst_height
|
||
|
dst_height = tmp
|
||
|
matrix.postScale(1f, - 1f)
|
||
|
matrix.postRotate(90f)
|
||
|
}
|
||
|
|
||
|
8 -> {
|
||
|
tmp = dst_width
|
||
|
|
||
|
dst_width = dst_height
|
||
|
dst_height = tmp
|
||
|
matrix.postRotate(- 90f)
|
||
|
}
|
||
|
|
||
|
else -> {
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// 表示領域に埋まるように平行移動
|
||
|
matrix.postTranslate(dst_width * 0.5f, dst_height * 0.5f)
|
||
|
|
||
|
// 出力用Bitmap作成
|
||
|
var dst : Bitmap? =
|
||
|
Bitmap.createBitmap(dst_width, dst_height, Bitmap.Config.ARGB_8888)
|
||
|
try {
|
||
|
return if(dst == null) {
|
||
|
showToast(context, false, "bitmap creation failed.")
|
||
|
null
|
||
|
} else {
|
||
|
val canvas = Canvas(dst)
|
||
|
val paint = Paint()
|
||
|
paint.isFilterBitmap = true
|
||
|
canvas.drawBitmap(sourceBitmap, matrix, paint)
|
||
|
BitmapUtils.log.d("createResizedBitmap: resized to %sx%s", dst_width, dst_height)
|
||
|
val tmp = dst
|
||
|
dst = null
|
||
|
tmp
|
||
|
}
|
||
|
} finally {
|
||
|
dst?.recycle()
|
||
|
}
|
||
|
} finally {
|
||
|
sourceBitmap.recycle()
|
||
|
}
|
||
|
} catch(ex : SecurityException) {
|
||
|
BitmapUtils.log.e(ex, "maybe we need pick up image again.")
|
||
|
} catch(ex : Throwable) {
|
||
|
BitmapUtils.log.trace(ex)
|
||
|
}
|
||
|
return null
|
||
|
}
|