Skip to content

Commit a432c3f

Browse files
committed
Support URI source for ImageScreenObject.
1 parent 8d40e8c commit a432c3f

File tree

3 files changed

+79
-22
lines changed

3 files changed

+79
-22
lines changed

haishinkit/src/main/java/com/haishinkit/screen/ImageScreenObject.kt

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,33 @@ package com.haishinkit.screen
22

33
import android.graphics.Bitmap
44
import android.graphics.BitmapFactory
5+
import android.net.Uri
56
import android.util.Base64
6-
import java.io.ByteArrayOutputStream
7+
import androidx.core.net.toUri
8+
import com.haishinkit.util.DataUriUtil
9+
10+
private sealed interface ImageSource {
11+
val uri: Uri
12+
13+
fun toBitmap(): Bitmap
14+
15+
class Data(override val uri: Uri) : ImageSource {
16+
override fun toBitmap(): Bitmap {
17+
val data = uri.schemeSpecificPart
18+
val base64 = data.substringAfter("base64,")
19+
val bytes = Base64.decode(base64, Base64.DEFAULT)
20+
return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
21+
}
22+
}
23+
24+
companion object {
25+
fun parseImageSource(uri: Uri?): ImageSource =
26+
when (uri?.scheme) {
27+
"data" -> Data(uri)
28+
else -> error("unsupported")
29+
}
30+
}
31+
}
732

833
/**
934
* An object that manages offscreen rendering an image source.
@@ -13,7 +38,7 @@ open class ImageScreenObject(
1338
) : ScreenObject(id) {
1439
private interface Keys {
1540
companion object {
16-
const val BITMAP: String = "bitmap"
41+
const val SOURCE: String = "source"
1742
}
1843
}
1944

@@ -26,14 +51,28 @@ open class ImageScreenObject(
2651
invalidateLayout()
2752
}
2853

54+
private var source: String? = null
55+
get() {
56+
if (field == null && bitmap != null) {
57+
return DataUriUtil.encode(bitmap!!)
58+
}
59+
return field
60+
}
61+
set(value) {
62+
field = value
63+
runCatching {
64+
bitmap = ImageSource.parseImageSource(source?.toUri()).toBitmap()
65+
}
66+
}
67+
2968
override var elements: Map<String, String>
3069
get() {
3170
return buildMap {
32-
put(Keys.BITMAP, bitmap?.toBase64() ?: "")
71+
put(Keys.SOURCE, source ?: "")
3372
}
3473
}
3574
set(value) {
36-
bitmap = value[Keys.BITMAP]?.toBitmap()
75+
source = value[Keys.SOURCE]
3776
}
3877

3978
init {
@@ -42,22 +81,5 @@ open class ImageScreenObject(
4281

4382
companion object {
4483
const val TYPE: String = "image"
45-
46-
private val TAG = VideoScreenObject::class.java.simpleName
4784
}
4885
}
49-
50-
private fun String.toBitmap(): Bitmap {
51-
val bytes = Base64.decode(this, Base64.NO_WRAP)
52-
return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
53-
}
54-
55-
private fun Bitmap.toBase64(
56-
format: Bitmap.CompressFormat = Bitmap.CompressFormat.PNG,
57-
quality: Int = 100,
58-
): String {
59-
val outputStream = ByteArrayOutputStream()
60-
compress(format, quality, outputStream)
61-
val bytes = outputStream.toByteArray()
62-
return Base64.encodeToString(bytes, Base64.NO_WRAP)
63-
}

haishinkit/src/main/java/com/haishinkit/screen/TextScreenObject.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,5 @@ class TextScreenObject(
9797

9898
companion object {
9999
const val TYPE: String = "text"
100-
private val TAG = VideoScreenObject::class.java.simpleName
101100
}
102101
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.haishinkit.util
2+
3+
import android.graphics.Bitmap
4+
import android.os.Build
5+
import android.util.Base64
6+
import java.io.ByteArrayOutputStream
7+
8+
internal object DataUriUtil {
9+
fun encode(
10+
bitmap: Bitmap,
11+
quality: Int = 90,
12+
): String {
13+
val bytes = encodeToBytes(bitmap, quality)
14+
val base64 = Base64.encodeToString(bytes, Base64.NO_WRAP)
15+
return "data:image/webp;base64,$base64"
16+
}
17+
18+
private fun encodeToBytes(
19+
bitmap: Bitmap,
20+
quality: Int,
21+
): ByteArray {
22+
val out = ByteArrayOutputStream()
23+
val format =
24+
if (Build.VERSION.SDK_INT >= 30) {
25+
if (bitmap.hasAlpha()) {
26+
Bitmap.CompressFormat.WEBP_LOSSLESS
27+
} else {
28+
Bitmap.CompressFormat.WEBP_LOSSY
29+
}
30+
} else {
31+
Bitmap.CompressFormat.WEBP
32+
}
33+
bitmap.compress(format, quality, out)
34+
return out.toByteArray()
35+
}
36+
}

0 commit comments

Comments
 (0)