Mercurial > cgi-bin > hgweb.cgi > SimpleResizer
comparison app/src/main/java/com/bartsent/simpleresizer/lib/getScaledInstance.kt @ 9:884092efe31a concur
Gets gratuitously killed. WTF?
author | David Barts <n5jrn@me.com> |
---|---|
date | Wed, 17 Feb 2021 13:20:25 -0800 |
parents | 9374d044a132 |
children | 62780d38a879 |
comparison
equal
deleted
inserted
replaced
7:9374d044a132 | 9:884092efe31a |
---|---|
1 package com.bartsent.simpleresizer.lib | 1 package com.bartsent.simpleresizer.lib |
2 | 2 |
3 import android.graphics.Bitmap | 3 import android.graphics.Bitmap |
4 import android.graphics.Canvas | 4 import android.graphics.Canvas |
5 import android.graphics.Color | |
5 import android.graphics.Matrix | 6 import android.graphics.Matrix |
7 import kotlin.math.ceil | |
8 import kotlin.math.floor | |
6 | 9 |
7 private data class IndexWeight(var index: Int, var weight: Double) | 10 private data class IndexWeight(var index: Int, var weight: Double) |
8 | 11 |
9 fun Bitmap.getScaledInstance(newWidth: Int, newHeight: Int, kernel: ScalingKernel = LanczosKernel): Bitmap { | 12 fun Bitmap.getScaledInstance(newWidth: Int, newHeight: Int, kernel: ScalingKernel = LanczosKernel): Bitmap { |
10 if (newWidth <= 0) | 13 if (newWidth <= 0) |
18 else { | 21 else { |
19 Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { | 22 Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { |
20 Canvas(it).drawBitmap(this, Matrix(), null) | 23 Canvas(it).drawBitmap(this, Matrix(), null) |
21 } | 24 } |
22 } | 25 } |
23 Resizer().use { resize -> | 26 if (width != newWidth) { |
24 if (width != newWidth) { | 27 if (height != newHeight) |
25 if (height != newHeight) | 28 return resizeVertical(resizeHorizontal(input, newWidth, kernel), newHeight, kernel) |
26 return resize.vertical(resize.horizontal(input, newWidth, kernel), newHeight, kernel) | 29 else |
27 else | 30 return resizeHorizontal(input, newWidth, kernel) |
28 return resize.horizontal(input, newWidth, kernel) | 31 } else { |
29 } else { | 32 return resizeVertical(input, newHeight, kernel) |
30 return resize.vertical(input, newHeight, kernel) | 33 } |
34 } | |
35 | |
36 private fun precomputeWeights(dstSize: Int, srcSize: Int, filter: ScalingKernel): Array<Array<IndexWeight>> { | |
37 val du = srcSize.toDouble() / dstSize.toDouble() | |
38 val scale = maxOf(1.0, du) | |
39 val ru = ceil(scale * filter.size) | |
40 val TEMPLATE = arrayOf<IndexWeight>() | |
41 val out = Array<Array<IndexWeight>>(dstSize) { TEMPLATE } | |
42 val tmp = ArrayList<IndexWeight>((ru.toInt()+2)*2) | |
43 val emax = srcSize - 1 | |
44 | |
45 for (v in 0 until dstSize) { | |
46 val fu = (v.toDouble()+0.5)*du - 0.5 | |
47 val begin = maxOf(0, ceil(fu - ru).toInt()) | |
48 val end = minOf(emax, floor(fu + ru).toInt()) | |
49 var sum: Double = 0.0 | |
50 for (u in begin..end) { | |
51 val w = filter.weight((u.toDouble() - fu) / scale) | |
52 if (w != 0.0) { | |
53 sum += w | |
54 tmp.add(IndexWeight(u, w)) | |
55 } | |
56 } | |
57 if (sum != 0.0) { | |
58 tmp.forEach { | |
59 it.weight /= sum | |
60 } | |
61 } | |
62 out[v] = tmp.toArray(TEMPLATE) | |
63 tmp.clear() | |
64 } | |
65 return out | |
66 } | |
67 | |
68 private fun clamp(v: Double): Int = minOf(255, maxOf(0, (v + 0.5).toInt())) | |
69 | |
70 private fun resample(target: Bitmap, x: Int, y: Int, weights: Array<IndexWeight>, scanLine: IntArray): Unit { | |
71 var r = 0.0; var g = 0.0; var b = 0.0; var a = 0.0 | |
72 weights.forEach { | |
73 val c = scanLine[it.index] | |
74 val aw = Color.alpha(c).toDouble() * it.weight | |
75 r += Color.red(c).toDouble() * aw | |
76 g += Color.green(c).toDouble() * aw | |
77 b += Color.blue(c).toDouble() * aw | |
78 a += aw | |
79 } | |
80 if (a == 0.0) | |
81 return | |
82 target.setPixel(x, y, Color.argb(clamp(a), clamp(r/a), clamp(g/a), clamp(b/a))) | |
83 } | |
84 | |
85 private fun resizeHorizontal(image: Bitmap, newWidth: Int, kernel: ScalingKernel): Bitmap { | |
86 val dst = Bitmap.createBitmap(newWidth, image.height, Bitmap.Config.ARGB_8888) | |
87 val weights = precomputeWeights(newWidth, image.width, kernel) | |
88 val scanLine = IntArray(image.width) | |
89 for (y in 0 until image.height) { | |
90 for (x in 0 until image.width) { | |
91 scanLine[x] = image.getPixel(x, y) | |
92 } | |
93 for (x in weights.indices) { | |
94 resample(dst, x, y, weights[x], scanLine) | |
31 } | 95 } |
32 } | 96 } |
97 return dst | |
33 } | 98 } |
99 | |
100 private fun resizeVertical(image: Bitmap, newHeight: Int, kernel: ScalingKernel): Bitmap { | |
101 val dst = Bitmap.createBitmap(image.width, newHeight, Bitmap.Config.ARGB_8888) | |
102 val weights = precomputeWeights(newHeight, image.height, kernel) | |
103 val scanLine = IntArray(image.height) | |
104 for (x in 0 until image.width) { | |
105 for (y in 0 until image.height) { | |
106 scanLine[y] = image.getPixel(x, y) | |
107 } | |
108 for (y in weights.indices) { | |
109 resample(dst, x, y, weights[y], scanLine) | |
110 } | |
111 } | |
112 return dst | |
113 } |