コード整理
This commit is contained in:
parent
1bf4d2b8c9
commit
3e83522143
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue