1 /* <lambda>null2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.test.silkfx.hdr 18 19 import android.content.Context 20 import android.graphics.Bitmap 21 import android.graphics.Canvas 22 import android.graphics.ColorMatrixColorFilter 23 import android.graphics.Gainmap 24 import android.graphics.ImageDecoder 25 import android.graphics.Paint 26 import android.util.AttributeSet 27 import android.view.View 28 import android.widget.AdapterView 29 import android.widget.ArrayAdapter 30 import android.widget.Button 31 import android.widget.FrameLayout 32 import android.widget.RadioGroup 33 import android.widget.Spinner 34 import android.widget.TextView 35 import com.android.test.silkfx.R 36 import com.davemorrissey.labs.subscaleview.ImageSource 37 import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView 38 39 class GainmapImage(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) { 40 41 private val gainmapImages: Array<String> 42 private var selectedImage = -1 43 private var outputMode = R.id.output_hdr 44 private var bitmap: Bitmap? = null 45 private var originalGainmap: Gainmap? = null 46 private var gainmapVisualizer: Bitmap? = null 47 private lateinit var imageView: SubsamplingScaleImageView 48 private lateinit var gainmapMetadataEditor: GainmapMetadataEditor 49 50 init { 51 gainmapImages = context.assets.list("gainmaps")!! 52 } 53 54 fun setImageSource(source: ImageDecoder.Source) { 55 findViewById<Spinner>(R.id.image_selection)!!.visibility = View.GONE 56 doDecode(source) 57 } 58 59 override fun onFinishInflate() { 60 super.onFinishInflate() 61 62 imageView = findViewById(R.id.image)!! 63 gainmapMetadataEditor = GainmapMetadataEditor(this, imageView) 64 65 findViewById<RadioGroup>(R.id.output_mode)!!.also { 66 it.check(outputMode) 67 it.setOnCheckedChangeListener { _, checkedId -> 68 outputMode = checkedId 69 updateDisplay() 70 } 71 } 72 73 val spinner = findViewById<Spinner>(R.id.image_selection)!! 74 val adapter = ArrayAdapter(context, android.R.layout.simple_spinner_item, gainmapImages) 75 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) 76 spinner.adapter = adapter 77 spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { 78 override fun onItemSelected( 79 parent: AdapterView<*>?, 80 view: View?, 81 position: Int, 82 id: Long 83 ) { 84 setImage(position) 85 } 86 87 override fun onNothingSelected(parent: AdapterView<*>?) { 88 } 89 } 90 91 findViewById<Button>(R.id.gainmap_metadata)!!.setOnClickListener { 92 gainmapMetadataEditor.openEditor() 93 } 94 95 setImage(0) 96 97 imageView.apply { 98 isClickable = true 99 setOnClickListener { 100 animate().alpha(.5f).withEndAction { 101 animate().alpha(1f).start() 102 }.start() 103 } 104 } 105 } 106 107 private fun setImage(position: Int) { 108 if (selectedImage == position) return 109 selectedImage = position 110 val source = ImageDecoder.createSource(resources.assets, 111 "gainmaps/${gainmapImages[position]}") 112 doDecode(source) 113 } 114 115 private fun doDecode(source: ImageDecoder.Source) { 116 originalGainmap = null 117 bitmap = ImageDecoder.decodeBitmap(source) { decoder, info, source -> 118 decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE 119 } 120 if (!bitmap!!.hasGainmap()) { 121 outputMode = R.id.output_sdr 122 findViewById<TextView>(R.id.error_msg)!!.also { 123 it.visibility = View.VISIBLE 124 it.text = "Image doesn't have a gainmap, only showing in SDR" 125 } 126 findViewById<RadioGroup>(R.id.output_mode)!!.also { 127 it.check(R.id.output_sdr) 128 it.visibility = View.GONE 129 } 130 } else { 131 findViewById<TextView>(R.id.error_msg)!!.visibility = View.GONE 132 findViewById<RadioGroup>(R.id.output_mode)!!.visibility = View.VISIBLE 133 134 val gainmap = bitmap!!.gainmap!! 135 originalGainmap = gainmap 136 gainmapMetadataEditor.setGainmap(Gainmap(gainmap, gainmap.gainmapContents)) 137 val map = gainmap.gainmapContents 138 if (map.config != Bitmap.Config.ALPHA_8) { 139 gainmapVisualizer = map 140 } else { 141 gainmapVisualizer = Bitmap.createBitmap(map.width, map.height, 142 Bitmap.Config.ARGB_8888) 143 val canvas = Canvas(gainmapVisualizer!!) 144 val paint = Paint() 145 paint.colorFilter = ColorMatrixColorFilter( 146 floatArrayOf( 147 0f, 0f, 0f, 1f, 0f, 148 0f, 0f, 0f, 1f, 0f, 149 0f, 0f, 0f, 1f, 0f, 150 0f, 0f, 0f, 0f, 255f 151 ) 152 ) 153 canvas.drawBitmap(map, 0f, 0f, paint) 154 canvas.setBitmap(null) 155 } 156 } 157 158 updateDisplay() 159 } 160 161 private fun updateDisplay() { 162 if (bitmap == null) return 163 164 imageView.setImage(ImageSource.cachedBitmap(when (outputMode) { 165 R.id.output_hdr -> { 166 bitmap!!.gainmap = originalGainmap 167 bitmap!! 168 } 169 170 R.id.output_hdr_test -> { 171 bitmap!!.gainmap = gainmapMetadataEditor.editedGainmap() 172 bitmap!! 173 } 174 175 R.id.output_sdr -> { 176 bitmap!!.gainmap = null; bitmap!! 177 } 178 179 R.id.output_gainmap -> gainmapVisualizer!! 180 else -> throw IllegalStateException() 181 })) 182 } 183 } 184