Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
Anton Potapov committed Oct 30, 2017
2 parents 72a22a0 + 34ff59f commit 0650804
Showing 1 changed file with 86 additions and 18 deletions.
104 changes: 86 additions & 18 deletions library/src/main/java/com/antonpotapov/Poliwhirl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.graphics.Color
import android.os.Handler
import android.os.Looper
import android.support.annotation.ColorInt
import android.support.annotation.NonNull
import android.util.Log
import com.antonpotapov.util.ColorUtils
import com.antonpotapov.util.SizeAwareArrayList
Expand Down Expand Up @@ -54,7 +55,9 @@ class Poliwhirl {
}
}

var borderSizeMul: Int = 16
var verticalBorderSizeMul: Int = 16
private set
var horizontalBorderSizeMul: Int = 16
private set
var minAvailableDistance: Int = 20
private set
Expand All @@ -66,6 +69,7 @@ class Poliwhirl {
request = createRequest()
}

@ColorInt
fun generate(bitmap: Bitmap): Int {
var result = 0
generateOnExecutor(bitmap, object : Callback {
Expand All @@ -76,43 +80,97 @@ class Poliwhirl {
return result
}

fun generateAsync(bitmap: Bitmap, callback: Callback) {
fun generateAsync(@NonNull bitmap: Bitmap, @NonNull callback: Callback) {
generateOnExecutor(bitmap, callback, asyncExecutor)
}

fun generateOnExecutor(bitmap: Bitmap, callback: Callback, executor: Executor): Request {
fun generateOnExecutor(@NonNull bitmap: Bitmap, @NonNull callback: Callback,
@NonNull executor: Executor): Request {
try {
return request.execute(bitmap, callback, executor, 0)
} finally {
request = createRequest()
}
}

fun generateOnExecutor(@NonNull bitmap: Bitmap, @NonNull callback: Callback,
@NonNull executor: Executor, forceNumThreads: Int): Request {
if (forceNumThreads < 0) throw IllegalArgumentException("provide legal threads number")
try {
return request.execute(bitmap, callback, executor)
return request.execute(bitmap, callback, executor, forceNumThreads)
} finally {
request = createRequest()
}
}

/**
* Step size in pixel when processing an image.
* For example: if [accuracy] is 3, algorithm will check every 3 pixel
*/
fun setAccuracy(accuracy: Int): Poliwhirl {
this.accuracy = accuracy
request.accuracy = accuracy
return this
}

/**
* Color distance calculated by CIEDE2000 formula. Colors with delta < minAvailableDistance
* will be processed as the same
*/
fun setMinAvailableColorDistance(minAvailableDistance: Int): Poliwhirl {
if (minAvailableDistance < 0) throw IllegalArgumentException("minAvailableDistance should be >= 0")
this.minAvailableDistance = minAvailableDistance
request.minAvailableDistance = minAvailableDistance
return this
}

/**
* Colors on the border of the image have more weight. So, this multiplier determines the size
* of this border.
* For example: if [borderSizeMul] is 16 than vertical borders will have width=image.width/16
*
* @see setHorizontalBorderSizeDivideMultiplier
*/
fun setVerticalBorderSizeDivideMultiplier(borderSizeMul: Int): Poliwhirl {
if (borderSizeMul <= 1) throw IllegalArgumentException("verticalBorderSizeMul should be > 1")
this.verticalBorderSizeMul = borderSizeMul
request.verticalBorderSizeMul = borderSizeMul
return this
}

/**
* Colors on the border of the image have more weight. So, this multiplier determines the size
* of this border.
* For example: if [borderSizeMul] is 16 than horizontal borders will have height=image.height/16
*
* @see setVerticalBorderSizeDivideMultiplier
*/
fun setHorizontalBorderSizeDivideMultiplier(borderSizeMul: Int): Poliwhirl {
if (borderSizeMul <= 1) throw IllegalArgumentException("horizontalBorderSizeMul should be > 1")
this.horizontalBorderSizeMul = borderSizeMul
request.horizontalBorderSizeMul = borderSizeMul
return this
}

/**
* Sets both vertical and horizontal [borderSizeMul]
*
* @see setVerticalBorderSizeDivideMultiplier
* @see setHorizontalBorderSizeDivideMultiplier
*/
fun setBorderSizeDivideMultiplier(borderSizeMul: Int): Poliwhirl {
this.borderSizeMul = borderSizeMul
request.borderSizeMul = borderSizeMul
setVerticalBorderSizeDivideMultiplier(borderSizeMul)
setHorizontalBorderSizeDivideMultiplier(borderSizeMul)
return this
}

private fun createRequest(): Request = Request(borderSizeMul, minAvailableDistance, accuracy)
private fun createRequest(): Request = Request(verticalBorderSizeMul, horizontalBorderSizeMul,
minAvailableDistance, accuracy)

class Request internal constructor(var borderSizeMul: Int,
class Request internal constructor(var verticalBorderSizeMul: Int,
var horizontalBorderSizeMul: Int,
var minAvailableDistance: Int,
var accuracy: Int) {


private var cornersMul: Double = 1.0
private var borderMul: Double = 1.0
private var baseMul: Double = 1.0
Expand All @@ -127,17 +185,21 @@ class Poliwhirl {

internal fun execute(bitmap: Bitmap,
callback: Callback,
executor: Executor): Request {
val verticalBorder = bitmap.height / borderSizeMul
val horizontalBorder = bitmap.width / borderSizeMul
executor: Executor,
forceNumThreads: Int): Request {
assertAccuracy(bitmap.width, bitmap.height)

val verticalBorder = bitmap.height / horizontalBorderSizeMul
val horizontalBorder = bitmap.width / verticalBorderSizeMul
updateMultipliers(horizontalBorder, verticalBorder, bitmap.width, bitmap.height)

val start = System.currentTimeMillis()

var currentlyFinishedThreadCount = 0
var numThreads = Math.max(0, Math.min(

var numThreads = if (forceNumThreads <= 0) Math.max(0, Math.min(
(executor as? ThreadPoolExecutor)?.maximumPoolSize ?: bitmap.height / accuracy,
MAXIMUM_POOL_SIZE))
MAXIMUM_POOL_SIZE)) else 0
if (bitmap.height * 2 < numThreads) {
numThreads = 1
}
Expand Down Expand Up @@ -176,6 +238,12 @@ class Poliwhirl {
return this
}

private fun assertAccuracy(bitmapWidth: Int, bitmapHeight: Int) {
if (accuracy > bitmapHeight) throw IllegalArgumentException("accuracy should be <= image height")
if (accuracy > bitmapWidth) throw IllegalArgumentException("accuracy should be <= image width")
if (accuracy <= 0) throw IllegalArgumentException("accuracy should be > 0")
}

private fun putColor(colors: SizeAwareArrayList<ColorGroup>, newColor: Int, newColormultiplier: Double) {
val newColorLab = ColorUtils.rgb2lab(Color.red(newColor), Color.green(newColor), Color.blue(newColor))
for (colorKey in colors) {
Expand Down Expand Up @@ -233,12 +301,12 @@ class Poliwhirl {
/**
* Adds multiplier for the provided color or adds it to the group if there is no such color yet
*/
fun addMultiplier(color: Int, additionalmultiplier: Double): ColorGroup {
fun addMultiplier(color: Int, additionalMultiplier: Double): ColorGroup {
synchronized(colors) {
this.multiplier += additionalmultiplier
this.multiplier += additionalMultiplier
for (colorInGroup in colors) {
if (colorInGroup.color == color) {
colorInGroup.colorMultiplier += additionalmultiplier
colorInGroup.colorMultiplier += additionalMultiplier
return this
}
}
Expand Down

0 comments on commit 0650804

Please sign in to comment.