コード整理

This commit is contained in:
tateisu 2023-05-14 15:56:18 +09:00
parent 1bf4d2b8c9
commit 3e83522143
5 changed files with 70 additions and 79 deletions

View File

@ -138,7 +138,7 @@ fun ActPost.addAttachment(
dialogOrToast("missing instance imformation.")
return
}
val mimeType = uri.resolveMimeType(mimeTypeArg, this, instance)
val mimeType = uri.resolveMimeType(mimeTypeArg, this)
?.notEmpty()
val isReply = states.inReplyToId != null

View File

@ -133,7 +133,7 @@ class AttachmentRequest(
pa.progress = context.getString(R.string.attachment_handling_compress)
val canUseWebP = try {
MIME_TYPE_WEBP.mimeTypeIsSupported(instance) && PrefB.bpUseWebP.value
PrefB.bpUseWebP.value && MIME_TYPE_WEBP.mimeTypeIsSupported(instance)
} catch (ex: Throwable) {
log.w(ex, "can't check canUseWebP")
false
@ -153,7 +153,7 @@ class AttachmentRequest(
context,
uri,
imageResizeConfig,
skipIfNoNeedToResizeAndRotate = canUseOriginal,
canSkip = canUseOriginal,
serverMaxSqPixel = serverMaxSqPixel
)?.let { bitmap ->
try {

View File

@ -349,7 +349,7 @@ class AttachmentUploader(
val (ti, ri) = TootInstance.get(client)
ti ?: return@runApiTask ri
val mimeType = src.uri.resolveMimeType(src.mimeType, safeContext, ti)
val mimeType = src.uri.resolveMimeType(src.mimeType, safeContext)
if (mimeType.isNullOrEmpty()) {
return@runApiTask TootApiResult(safeContext.getString(R.string.mime_type_missing))
}

View File

@ -228,27 +228,36 @@ private fun findMimeTypeByFileHeader(
return null
}
private fun String.isProblematicImageType(instance: TootInstance) = when (instance.instanceType) {
InstanceType.Mastodon -> when (this) {
// https://github.com/mastodon/mastodon/issues/23588
"image/heic", "image/heif" -> true
// https://github.com/mastodon/mastodon/issues/20834
"image/avif" -> true
/**
* issueを抱えたmimeTypeなら真
* - サーバ情報にある利用可能mimeTypeリストがアテにならん
*/
private fun String.isProblematicImageType(instance: TootInstance) =
when (instance.instanceType) {
InstanceType.Mastodon -> when (this) {
// https://github.com/mastodon/mastodon/issues/23588
"image/heic", "image/heif" -> true
// https://github.com/mastodon/mastodon/issues/20834
"image/avif" -> true
else -> false
}
InstanceType.Pixelfed -> when (this) {
// Pixelfed は PC Web UI で画像を開くダイアログの時点でHEIC,HEIF,AVIF を選択できない
"image/heic", "image/heif", "image/avif" -> true
else -> false
}
// PleromaやMisskeyでの問題は調べてない
else -> false
}
InstanceType.Pixelfed -> when (this) {
// Pixelfed は PC Web UI で画像を開くダイアログの時点でHEIC,HEIF,AVIF を選択できない
"image/heic", "image/heif", "image/avif" -> true
else -> false
}
// PleromaやMisskeyでの問題は調べてない
else -> false
}
fun String.mimeTypeIsSupportedByServer(instance: TootInstance) =
instance.configuration
/**
* サーバに送信できるmimeTypeなら真
*/
fun String.mimeTypeIsSupported(instance: TootInstance) = when {
isProblematicImageType(instance) -> false
else -> instance.configuration
?.jsonObject("media_attachments")
?.jsonArray("supported_mime_types")
?.contains(this)
@ -256,24 +265,15 @@ fun String.mimeTypeIsSupportedByServer(instance: TootInstance) =
InstanceType.Pixelfed -> acceptableMimeTypesPixelfed
else -> acceptableMimeTypes
}.contains(this)
fun String.mimeTypeIsSupported(instance: TootInstance) = when {
isProblematicImageType(instance) -> false
else -> mimeTypeIsSupportedByServer(instance)
}
fun Uri.resolveMimeType(
mimeTypeArg1: String?,
context: Context,
instance: TootInstance,
): String? {
fun Uri.resolveMimeType(mimeTypeArg1: String?, context: Context): String? {
// BitmapFactory で静止画の mimeType を調べる
// image/j()pg だの image/j(e)pg だの、mime type を誤記するアプリがあまりに多い
// application/octet-stream などが誤設定されてることもある
// Androidが静止画を読めるならそのmimeType
bitmapMimeType(context.contentResolver)?.notEmpty()?.let { return it }
// 動画の一部は音声かもしれない
// データに動画や音声が含まれるか調べる
// MediaMetadataRetriever で動画/音声の mimeType を調べる
try {
MediaMetadataRetriever().use { mmr ->
mmr.setDataSource(context, this)
@ -283,37 +283,40 @@ fun Uri.resolveMimeType(
log.w(ex, "not video or audio.")
}
// 引数のmimeTypeがサーバでサポートされているならソレ
try {
mimeTypeArg1
?.notEmpty()
?.takeIf { it.mimeTypeIsSupportedByServer(instance) }
?.let { return it }
} catch (ex: Throwable) {
AttachmentUploader.log.w(ex, "mimeTypeArg1 check failed.")
}
// ContentResolverに尋ねる
try {
context.contentResolver.getType(this)
?.notEmpty()
?.takeIf { it.mimeTypeIsSupportedByServer(instance) }
?.let { return it }
} catch (ex: Throwable) {
AttachmentUploader.log.w(ex, "contentResolver.getType failed.")
log.w(ex, "contentResolver.getType failed.")
}
// gboardのステッカーではUriのクエリパラメータにmimeType引数がある
try {
getQueryParameter("mimeType")
?.notEmpty()
?.takeIf { it.mimeTypeIsSupportedByServer(instance) }
?.let { return it }
} catch (ex: Throwable) {
log.w(ex, "getQueryParameter(mimeType) failed.")
}
// ファイルヘッダを読んで判定する
findMimeTypeByFileHeader(context.contentResolver, this)
?.notEmpty()?.let { return it }
// 引数のmimeTypeがサーバでサポートされているならソレ
try {
mimeTypeArg1
?.notEmpty()
?.let { return it }
} catch (ex: Throwable) {
log.w(ex, "mimeTypeArg1 check failed.")
}
try {
// ファイルヘッダを読んで判定する
findMimeTypeByFileHeader(context.contentResolver, this)
?.notEmpty()?.let { return it }
} catch (ex: Throwable) {
log.w(ex, "findMimeTypeByFileHeader check failed.")
}
return null
}

View File

@ -123,7 +123,7 @@ fun createResizedBitmap(
else -> ResizeConfig(ResizeType.LongSide, sizeLongSide)
},
serverMaxSqPixel = serverMaxSqPixel,
skipIfNoNeedToResizeAndRotate = skipIfNoNeedToResizeAndRotate
canSkip = skipIfNoNeedToResizeAndRotate
)
fun Uri.bitmapMimeType(contentResolver: ContentResolver): String? =
@ -153,9 +153,8 @@ fun createResizedBitmap(
serverMaxSqPixel: Int? = null,
// 真の場合、リサイズも回転も必要ないならnullを返す
skipIfNoNeedToResizeAndRotate: Boolean = false,
canSkip: Boolean = false,
): Bitmap? {
try {
val orientation: Int? = context.contentResolver.openInputStream(uri)?.use {
it.imageOrientation()
@ -184,24 +183,16 @@ fun createResizedBitmap(
/// 出力サイズの計算
val sizeSpec = resizeConfig.size.toFloat()
var dstSize: PointF = when (resizeConfig.type) {
ResizeType.None -> srcSize
ResizeType.SquarePixel ->
srcSize.limitBySqPixel(aspect, sizeSpec * sizeSpec)
ResizeType.LongSide -> when {
max(srcSize.x, srcSize.y) <= resizeConfig.size -> srcSize
aspect >= 1f -> PointF(
resizeConfig.size.toFloat(),
sizeSpec / aspect
)
else -> PointF(
sizeSpec * aspect,
resizeConfig.size.toFloat()
)
aspect >= 1f -> PointF(sizeSpec, sizeSpec / aspect)
else -> PointF(sizeSpec * aspect, sizeSpec)
}
ResizeType.SquarePixel -> srcSize.limitBySqPixel(aspect, sizeSpec * sizeSpec)
}
if (serverMaxSqPixel != null && serverMaxSqPixel > 0) {
@ -230,9 +221,9 @@ fun createResizedBitmap(
)
// リサイズも回転も必要がない場合
if (skipIfNoNeedToResizeAndRotate &&
(orientation == null || orientation == 1) &&
!resizeRequired
if (canSkip &&
!resizeRequired &&
(orientation == null || orientation == 1)
) {
log.w("createResizedBitmap: no need to resize or rotate.")
return null
@ -256,10 +247,10 @@ fun createResizedBitmap(
// inSampleSizeを計算
var bits = 0
var x = max(srcSize.x, srcSize.y).toInt()
while (x > 4096 || (x > 512 && x > dstMax * 2)) {
var n = max(srcSize.x, srcSize.y).toInt()
while (n > 4096 || (n > 512 && n > dstMax * 2)) {
++bits
x = x shr 1
n = n shr 1
}
options.inJustDecodeBounds = false
options.inSampleSize = 1 shl bits
@ -277,7 +268,6 @@ fun createResizedBitmap(
// サンプル数が変化している
srcWidth = options.outWidth
srcHeight = options.outHeight
val scale = dstMax.toFloat() / max(srcWidth, srcHeight)
val matrix = Matrix().apply {
reset()
@ -286,6 +276,7 @@ fun createResizedBitmap(
postTranslate(srcWidth * -0.5f, srcHeight * -0.5f)
// スケーリング
val scale = dstMax.toFloat() / max(srcWidth, srcHeight)
postScale(scale, scale)
// 回転情報があれば回転
@ -296,24 +287,21 @@ fun createResizedBitmap(
}
// 出力用Bitmap作成
var dst: Bitmap? =
Bitmap.createBitmap(dstSizeInt.x, dstSizeInt.y, Bitmap.Config.ARGB_8888)
val dst = Bitmap.createBitmap(dstSizeInt.x, dstSizeInt.y, Bitmap.Config.ARGB_8888)
try {
return if (dst == null) {
if (dst == null) {
context.showToast(false, "bitmap creation failed.")
null
} else {
val canvas = Canvas(dst)
val paint = Paint()
paint.isFilterBitmap = true
canvas.drawBitmap(sourceBitmap, matrix, paint)
log.d("createResizedBitmap: resized to ${dstSizeInt.x}x${dstSizeInt.y}")
val tmp = dst
dst = null
tmp
return dst
}
} finally {
} catch (ex: Throwable) {
dst?.recycle()
throw ex
}
} finally {
sourceBitmap.recycle()