annotate app/src/main/java/com/bartsent/simpleresizer/lib/getScaledInstance.kt @ 6:e8059b166de1

Lanczos works, but is painfully slow.
author David Barts <n5jrn@me.com>
date Tue, 16 Feb 2021 17:29:52 -0800
parents
children 9374d044a132 b1605be35bcc
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
1 package com.bartsent.simpleresizer.lib
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
2
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
3 import android.graphics.Bitmap
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
4 import android.graphics.Canvas
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
5 import android.graphics.Color
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
6 import android.graphics.Matrix
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
7 import kotlin.math.ceil
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
8 import kotlin.math.floor
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
9
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
10 private data class IndexWeight(var index: Int, var weight: Double)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
11
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
12 fun Bitmap.getScaledInstance(newWidth: Int, newHeight: Int, kernel: ScalingKernel = LanczosKernel): Bitmap {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
13 if (newWidth <= 0)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
14 throw IllegalArgumentException("invalid width: $newWidth")
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
15 if (newHeight <= 0)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
16 throw IllegalArgumentException("invalid height: $newHeight")
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
17 if (width == newWidth && height == newHeight)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
18 return Bitmap.createBitmap(this)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
19 val input = if (config == Bitmap.Config.ARGB_8888)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
20 this
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
21 else {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
22 Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
23 Canvas(it).drawBitmap(this, Matrix(), null)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
24 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
25 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
26 if (width != newWidth) {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
27 if (height != newHeight)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
28 return resizeVertical(resizeHorizontal(input, newWidth, kernel), newHeight, kernel)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
29 else
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
30 return resizeHorizontal(input, newWidth, kernel)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
31 } else {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
32 return resizeVertical(input, newHeight, kernel)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
33 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
34 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
35
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
36 private fun precomputeWeights(dstSize: Int, srcSize: Int, filter: ScalingKernel): Array<Array<IndexWeight>> {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
37 val du = srcSize.toDouble() / dstSize.toDouble()
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
38 val scale = maxOf(1.0, du)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
39 val ru = ceil(scale * filter.size)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
40 val TEMPLATE = arrayOf<IndexWeight>()
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
41 val out = Array<Array<IndexWeight>>(dstSize) { TEMPLATE }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
42 val tmp = ArrayList<IndexWeight>((ru.toInt()+2)*2)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
43 val emax = srcSize - 1
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
44
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
45 for (v in 0 until dstSize) {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
46 val fu = (v.toDouble()+0.5)*du - 0.5
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
47 val begin = maxOf(0, ceil(fu - ru).toInt())
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
48 val end = minOf(emax, floor(fu + ru).toInt())
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
49 var sum: Double = 0.0
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
50 for (u in begin..end) {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
51 val w = filter.weight((u.toDouble() - fu) / scale)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
52 if (w != 0.0) {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
53 sum += w
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
54 tmp.add(IndexWeight(u, w))
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
55 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
56 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
57 if (sum != 0.0) {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
58 tmp.forEach {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
59 it.weight /= sum
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
60 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
61 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
62 out[v] = tmp.toArray(TEMPLATE)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
63 tmp.clear()
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
64 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
65 return out
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
66 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
67
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
68 private fun clamp(v: Double): Int = minOf(255, maxOf(0, (v + 0.5).toInt()))
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
69
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
70 private fun resample(target: Bitmap, x: Int, y: Int, weights: Array<IndexWeight>, scanLine: IntArray): Unit {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
71 var r = 0.0; var g = 0.0; var b = 0.0; var a = 0.0
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
72 weights.forEach {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
73 val c = scanLine[it.index]
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
74 val aw = Color.alpha(c).toDouble() * it.weight
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
75 r += Color.red(c).toDouble() * aw
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
76 g += Color.green(c).toDouble() * aw
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
77 b += Color.blue(c).toDouble() * aw
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
78 a += aw
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
79 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
80 if (a == 0.0)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
81 return
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
82 target.setPixel(x, y, Color.argb(clamp(a), clamp(r/a), clamp(g/a), clamp(b/a)))
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
83 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
84
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
85 private fun resizeHorizontal(image: Bitmap, newWidth: Int, kernel: ScalingKernel): Bitmap {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
86 val dst = Bitmap.createBitmap(newWidth, image.height, Bitmap.Config.ARGB_8888)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
87 val weights = precomputeWeights(newWidth, image.width, kernel)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
88 val scanLine = IntArray(image.width)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
89 for (y in 0 until image.height) {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
90 for (x in 0 until image.width) {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
91 scanLine[x] = image.getPixel(x, y)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
92 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
93 for (x in weights.indices) {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
94 resample(dst, x, y, weights[x], scanLine)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
95 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
96 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
97 return dst
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
98 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
99
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
100 private fun resizeVertical(image: Bitmap, newHeight: Int, kernel: ScalingKernel): Bitmap {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
101 val dst = Bitmap.createBitmap(image.width, newHeight, Bitmap.Config.ARGB_8888)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
102 val weights = precomputeWeights(newHeight, image.height, kernel)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
103 val scanLine = IntArray(image.height)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
104 for (x in 0 until image.width) {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
105 for (y in 0 until image.height) {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
106 scanLine[y] = image.getPixel(x, y)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
107 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
108 for (y in weights.indices) {
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
109 resample(dst, x, y, weights[y], scanLine)
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
110 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
111 }
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
112 return dst
e8059b166de1 Lanczos works, but is painfully slow.
David Barts <n5jrn@me.com>
parents:
diff changeset
113 }