SilkFX HDR demos

Test: this
Bug: 266628247
Change-Id: Ib41de2de8634e03dd6f7f6b3909e4e109793fa31
This commit is contained in:
John Reck
2023-02-14 19:40:20 -05:00
parent 01472127c0
commit 9f85cd3b70
24 changed files with 868 additions and 24 deletions

View File

@@ -48,10 +48,7 @@ void DrawGainmapBitmap(SkCanvas* c, const sk_sp<const SkImage>& image, const SkR
gainmapSrc.fRight *= sX;
gainmapSrc.fTop *= sY;
gainmapSrc.fBottom *= sY;
// TODO: Temporary workaround for SkGainmapShader::Make not having a const variant
sk_sp<SkImage> mutImage = sk_ref_sp(const_cast<SkImage*>(image.get()));
sk_sp<SkImage> mutGainmap = sk_ref_sp(const_cast<SkImage*>(gainmapImage.get()));
auto shader = SkGainmapShader::Make(mutImage, src, sampling, mutGainmap, gainmapSrc,
auto shader = SkGainmapShader::Make(image, src, sampling, gainmapImage, gainmapSrc,
sampling, gainmapInfo, dst, targetSdrHdrRatio,
c->imageInfo().refColorSpace());
gainmapPaint.setShader(shader);

View File

@@ -25,13 +25,17 @@ package {
android_test {
name: "SilkFX",
srcs: ["**/*.java", "**/*.kt"],
srcs: [
"**/*.java",
"**/*.kt",
],
platform_apis: true,
certificate: "platform",
static_libs: [
static_libs: [
"androidx.core_core",
"androidx.appcompat_appcompat",
"com.google.android.material_material",
"androidx-constraintlayout_constraintlayout",
"subsampling-scale-image-view",
],
}

View File

@@ -55,5 +55,15 @@
android:exported="true">
</activity>
<activity android:name=".app.HdrImageViewer"
android:label="HDR Gainmap Image Viewer"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/*"/>
</intent-filter>
</activity>
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 MiB

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#000000"
android:endColor="#0000FF"
android:angle="0"/>
</shape>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#000000"
android:endColor="#181818"
android:angle="0"/>
</shape>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#000000"
android:endColor="#00FF00"
android:angle="0"/>
</shape>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#000000"
android:endColor="#FFFFFF"
android:angle="0"/>
</shape>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#E8E8E8"
android:endColor="#FFFFFF"
android:angle="0"/>
</shape>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#000000"
android:endColor="#FF0000"
android:angle="0"/>
</shape>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<com.android.test.silkfx.hdr.ColorGrid xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" />

View File

@@ -24,16 +24,6 @@
<FrameLayout android:id="@+id/demo_container"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<com.android.test.silkfx.common.HDRIndicator
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="8dp" />
android:layout_height="match_parent" />
</LinearLayout>

View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<com.android.test.silkfx.hdr.GainmapDecodeTest xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/decode_full"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Decode full" />
<Button
android:id="@+id/decode_subsampled4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Decode subsampled (1/4th)" />
<Button
android:id="@+id/decode_scaled66"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Decode scaled (66%)" />
<Button
android:id="@+id/decode_crop"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Decode croppedSquare" />
<Button
android:id="@+id/decode_cropScaled33"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Decode croppedSquare(33%)" />
</LinearLayout>
<TextView
android:id="@+id/source_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1">
<TextView
android:id="@+id/sdr_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/sdr_source"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"
android:scaleType="fitStart" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1">
<TextView
android:id="@+id/gainmap_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/gainmap"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"
android:scaleType="fitStart" />
</LinearLayout>
</LinearLayout>
</com.android.test.silkfx.hdr.GainmapDecodeTest>

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<com.android.test.silkfx.hdr.GainmapImage xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/gainmap_image">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RadioGroup android:id="@+id/output_mode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton android:id="@+id/output_sdr"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="SDR original" />
<RadioButton android:id="@+id/output_gainmap"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Gainmap" />
<RadioButton android:id="@+id/output_hdr"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="HDR (sdr+gainmap)" />
</RadioGroup>
<Spinner
android:id="@+id/image_selection"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/error_msg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
<com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</com.android.test.silkfx.hdr.GainmapImage>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View android:background="@drawable/dark_gradient"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<View android:background="@drawable/light_gradient"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<View android:background="@drawable/grey_sweep_gradient"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<View android:background="@drawable/red_sweep_gradient"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<View android:background="@drawable/green_sweep_gradient"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<View android:background="@drawable/blue_sweep_gradient"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/color_mode_controls" />
<include layout="@layout/gainmap_image" />
</LinearLayout>

View File

@@ -26,6 +26,7 @@ import android.widget.BaseExpandableListAdapter
import android.widget.ExpandableListView
import android.widget.TextView
import com.android.test.silkfx.app.CommonDemoActivity
import com.android.test.silkfx.app.EXTRA_COMMON_CONTROLS
import com.android.test.silkfx.app.EXTRA_LAYOUT
import com.android.test.silkfx.app.EXTRA_TITLE
import com.android.test.silkfx.hdr.GlowActivity
@@ -37,10 +38,11 @@ class Demo(val name: String, val makeIntent: (Context) -> Intent) {
constructor(name: String, activity: KClass<out Activity>) : this(name, { context ->
Intent(context, activity.java)
})
constructor(name: String, layout: Int) : this(name, { context ->
constructor(name: String, layout: Int, commonControls: Boolean = true) : this(name, { context ->
Intent(context, CommonDemoActivity::class.java).apply {
putExtra(EXTRA_LAYOUT, layout)
putExtra(EXTRA_TITLE, name)
putExtra(EXTRA_COMMON_CONTROLS, commonControls)
}
})
}
@@ -49,7 +51,11 @@ data class DemoGroup(val groupName: String, val demos: List<Demo>)
private val AllDemos = listOf(
DemoGroup("HDR", listOf(
Demo("Glow", GlowActivity::class),
Demo("Blingy Notifications", R.layout.bling_notifications)
Demo("Blingy Notifications", R.layout.bling_notifications),
Demo("Color Grid", R.layout.color_grid),
Demo("Gradient Sweep", R.layout.gradient_sweep),
Demo("Gainmap Image", R.layout.gainmap_image),
Demo("Gainmap Decode Test", R.layout.gainmap_decode_test, commonControls = false)
)),
DemoGroup("Materials", listOf(
Demo("Glass", GlassActivity::class),

View File

@@ -22,6 +22,7 @@ import android.view.LayoutInflater
const val EXTRA_LAYOUT = "layout"
const val EXTRA_TITLE = "title"
const val EXTRA_COMMON_CONTROLS = "common_controls"
class CommonDemoActivity : BaseDemoActivity() {
@@ -38,8 +39,13 @@ class CommonDemoActivity : BaseDemoActivity() {
val title = extras.getString(EXTRA_TITLE, "SilkFX")
window.setTitle(title)
setContentView(R.layout.common_base)
if (extras.getBoolean(EXTRA_COMMON_CONTROLS, true)) {
setContentView(R.layout.common_base)
LayoutInflater.from(this).inflate(layout, findViewById(R.id.demo_container), true)
} else {
setContentView(layout)
}
actionBar?.title = title
LayoutInflater.from(this).inflate(layout, findViewById(R.id.demo_container), true)
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.silkfx.app
import android.content.Intent
import android.graphics.ImageDecoder
import android.os.Bundle
import com.android.test.silkfx.R
import com.android.test.silkfx.hdr.GainmapImage
class HdrImageViewer : BaseDemoActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.hdr_image_viewer)
val intent = this.intent ?: return finish()
if (Intent.ACTION_VIEW != intent.action) {
finish()
return
}
val data = intent.data ?: return finish()
val source = ImageDecoder.createSource(contentResolver, data)
findViewById<GainmapImage>(R.id.gainmap_image)!!.setImageSource(source)
}
}

View File

@@ -23,8 +23,11 @@ import android.util.AttributeSet
import android.view.View
open class BaseDrawingView : View {
val sRGB = ColorSpace.get(ColorSpace.Named.SRGB)
val displayP3 = ColorSpace.get(ColorSpace.Named.DISPLAY_P3)
val scRGB = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)
val bt2020 = ColorSpace.get(ColorSpace.Named.BT2020)
val bt2020_pq = ColorSpace.get(ColorSpace.Named.BT2020_PQ)
val lab = ColorSpace.get(ColorSpace.Named.CIE_LAB)
val density: Float

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.silkfx.hdr
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.ColorSpace
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import com.android.test.silkfx.common.BaseDrawingView
class ColorGrid(context: Context, attrs: AttributeSet?) : BaseDrawingView(context, attrs) {
init {
isClickable = true
setOnClickListener {
invalidate()
}
}
fun toMaxColor(color: Int, colorspace: ColorSpace): Long {
val red = (Color.red(color) / 255f) * colorspace.getMaxValue(0)
val green = (Color.green(color) / 255f) * colorspace.getMaxValue(1)
val blue = (Color.blue(color) / 255f) * colorspace.getMaxValue(2)
val alpha = Color.alpha(color) / 255f
return Color.pack(red, green, blue, alpha, colorspace)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val paint = Paint()
paint.isDither = true
paint.isAntiAlias = true
paint.textSize = 18.dp()
paint.textAlign = Paint.Align.LEFT
val labels = arrayOf("sRGB", "Display P3", "BT2020_PQ", "scRGB(max)")
val colorSpaces = arrayOf(sRGB, displayP3, bt2020_pq, scRGB)
val colWidth = width / colorSpaces.size.toFloat()
val rowHeight = minOf((height - 20.dp()) / 4f, colWidth)
val dest = Rect(0, 0, rowHeight.toInt(), colWidth.toInt())
for (colIndex in labels.indices) {
canvas.save()
canvas.translate(colIndex * colWidth, 20.dp())
paint.color = Color.WHITE
canvas.drawText(labels[colIndex], 0f, 1f, paint)
arrayOf(Color.WHITE, Color.RED, Color.BLUE, Color.GREEN).forEach {
paint.setColor(toMaxColor(it, colorSpaces[colIndex]))
canvas.drawRect(dest, paint)
canvas.translate(0f, rowHeight)
}
canvas.restore()
}
}
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.silkfx.hdr
import android.content.Context
import android.graphics.ImageDecoder
import android.graphics.Rect
import android.util.AttributeSet
import android.widget.Button
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import com.android.test.silkfx.R
enum class DecodeMode {
Full,
Subsampled4,
Scaled66,
CropedSquared,
CropedSquaredScaled33
}
class GainmapDecodeTest(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
private fun decode(mode: DecodeMode) {
val source = ImageDecoder.createSource(resources.assets,
"gainmaps/cave.jpg")
val sourceInfo = findViewById<TextView>(R.id.source_info)!!
val gainmapImage = ImageDecoder.decodeBitmap(source) { decoder, info, source ->
decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
sourceInfo.text =
"Original size ${info.size.width}x${info.size.height}; mime-type = ${info.mimeType}"
when (mode) {
DecodeMode.Full -> {}
DecodeMode.Subsampled4 -> {
decoder.setTargetSampleSize(4)
}
DecodeMode.Scaled66 -> {
val size = info.size
decoder.setTargetSize((size.width * .66).toInt(), (size.height * .66).toInt())
}
DecodeMode.CropedSquared -> {
val dimen = minOf(info.size.width, info.size.height)
decoder.crop = Rect(50, 50, dimen - 100, dimen - 100)
}
DecodeMode.CropedSquaredScaled33 -> {
val size = info.size
val targetWidth = (size.width * .33).toInt()
val targetHeight = (size.height * .33).toInt()
decoder.setTargetSize(targetWidth, targetHeight)
val dimen = minOf(targetWidth, targetHeight)
decoder.crop = Rect(50, 50, dimen - 100, dimen - 100)
}
}
}
val gainmapContents = gainmapImage.gainmap!!.gainmapContents!!
val sdrBitmap = gainmapImage.also { it.gainmap = null }
findViewById<ImageView>(R.id.sdr_source)!!.setImageBitmap(sdrBitmap)
findViewById<TextView>(R.id.sdr_label)!!.text =
"SDR Size: ${sdrBitmap.width}x${sdrBitmap.height}"
findViewById<ImageView>(R.id.gainmap)!!.setImageBitmap(gainmapContents)
findViewById<TextView>(R.id.gainmap_label)!!.text =
"Gainmap Size: ${gainmapContents.width}x${gainmapContents.height}"
}
override fun onFinishInflate() {
super.onFinishInflate()
decode(DecodeMode.Full)
findViewById<Button>(R.id.decode_full)!!.setOnClickListener {
decode(DecodeMode.Full)
}
findViewById<Button>(R.id.decode_subsampled4)!!.setOnClickListener {
decode(DecodeMode.Subsampled4)
}
findViewById<Button>(R.id.decode_scaled66)!!.setOnClickListener {
decode(DecodeMode.Scaled66)
}
findViewById<Button>(R.id.decode_crop)!!.setOnClickListener {
decode(DecodeMode.CropedSquared)
}
findViewById<Button>(R.id.decode_cropScaled33)!!.setOnClickListener {
decode(DecodeMode.CropedSquaredScaled33)
}
}
}

View File

@@ -0,0 +1,183 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.silkfx.hdr
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.ColorMatrixColorFilter
import android.graphics.Gainmap
import android.graphics.ImageDecoder
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.FrameLayout
import android.widget.RadioGroup
import android.widget.Spinner
import android.widget.TextView
import com.android.test.silkfx.R
import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
class GainmapImage(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
private val gainmapImages: Array<String>
private var selectedImage = -1
private var outputMode = R.id.output_hdr
private var bitmap: Bitmap? = null
private var gainmap: Gainmap? = null
private var gainmapVisualizer: Bitmap? = null
private lateinit var imageView: SubsamplingScaleImageView
init {
gainmapImages = context.assets.list("gainmaps")!!
}
fun setImageSource(source: ImageDecoder.Source) {
findViewById<Spinner>(R.id.image_selection)!!.visibility = View.GONE
doDecode(source)
}
override fun onFinishInflate() {
super.onFinishInflate()
imageView = findViewById(R.id.image)!!
findViewById<RadioGroup>(R.id.output_mode)!!.also {
it.check(outputMode)
it.setOnCheckedChangeListener { _, checkedId ->
val previousMode = outputMode
outputMode = checkedId
if (previousMode == R.id.output_sdr && checkedId == R.id.output_hdr) {
animateToHdr()
} else if (previousMode == R.id.output_hdr && checkedId == R.id.output_sdr) {
animateToSdr()
} else {
updateDisplay()
}
}
}
val spinner = findViewById<Spinner>(R.id.image_selection)!!
val adapter = ArrayAdapter(context, android.R.layout.simple_spinner_item, gainmapImages)
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = adapter
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
setImage(position)
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
setImage(gainmapImages.indexOf("cave.jpg"))
imageView.apply {
isClickable = true
setOnClickListener {
animate().alpha(.5f).withEndAction {
animate().alpha(1f).start()
}.start()
}
}
}
private fun setImage(position: Int) {
if (selectedImage == position) return
selectedImage = position
val source = ImageDecoder.createSource(resources.assets,
"gainmaps/${gainmapImages[position]}")
doDecode(source)
}
private fun doDecode(source: ImageDecoder.Source) {
gainmap = null
bitmap = ImageDecoder.decodeBitmap(source) { decoder, info, source ->
decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
}
if (!bitmap!!.hasGainmap()) {
outputMode = R.id.output_sdr
findViewById<TextView>(R.id.error_msg)!!.also {
it.visibility = View.VISIBLE
it.text = "Image doesn't have a gainmap, only showing in SDR"
}
findViewById<RadioGroup>(R.id.output_mode)!!.also {
it.check(R.id.output_sdr)
it.visibility = View.GONE
}
} else {
findViewById<TextView>(R.id.error_msg)!!.visibility = View.GONE
findViewById<RadioGroup>(R.id.output_mode)!!.visibility = View.VISIBLE
gainmap = bitmap!!.gainmap
val map = gainmap!!.gainmapContents
if (map.config != Bitmap.Config.ALPHA_8) {
gainmapVisualizer = map
} else {
gainmapVisualizer = Bitmap.createBitmap(map.width, map.height,
Bitmap.Config.ARGB_8888)
val canvas = Canvas(gainmapVisualizer!!)
val paint = Paint()
paint.colorFilter = ColorMatrixColorFilter(
floatArrayOf(
0f, 0f, 0f, 1f, 0f,
0f, 0f, 0f, 1f, 0f,
0f, 0f, 0f, 1f, 0f,
0f, 0f, 0f, 0f, 255f
)
)
canvas.drawBitmap(map, 0f, 0f, paint)
canvas.setBitmap(null)
}
}
updateDisplay()
}
private fun animateToHdr() {
if (bitmap == null || gainmap == null) return
// TODO: Trigger an animation
updateDisplay()
}
private fun animateToSdr() {
if (bitmap == null) return
// TODO: Trigger an animation
updateDisplay()
}
private fun updateDisplay() {
if (bitmap == null) return
imageView.setImage(ImageSource.cachedBitmap(when (outputMode) {
R.id.output_hdr -> { bitmap!!.gainmap = gainmap; bitmap!! }
R.id.output_sdr -> { bitmap!!.gainmap = null; bitmap!! }
R.id.output_gainmap -> gainmapVisualizer!!
else -> throw IllegalStateException()
}))
}
}

View File

@@ -26,9 +26,7 @@ import android.util.AttributeSet
import com.android.test.silkfx.common.BaseDrawingView
import kotlin.math.min
class RadialGlow : BaseDrawingView {
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
class RadialGlow(context: Context, attrs: AttributeSet?) : BaseDrawingView(context, attrs) {
var glowToggle = false