Skip to content

Commit

Permalink
Merge pull request #1706 from HenrikJannsen/bisq-avatar-improvements
Browse files Browse the repository at this point in the history
Bisq avatar improvements
  • Loading branch information
alvasw authored Feb 29, 2024
2 parents a5b9a03 + 18dc6ee commit 793b50e
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 321 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.desktop.components.cathash;

import bisq.common.util.MathUtils;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class BucketConfig {
static final String DIGIT = "#";

private static final int BG0_COUNT = 16;
private static final int BG1_COUNT = 16;
private static final int EARS0_COUNT = 16;
private static final int EARS1_COUNT = 3;
private static final int FACE0_COUNT = 16;
private static final int FACE1_COUNT = 9;
private static final int EYES0_COUNT = 16;
private static final int NOSE0_COUNT = 6;
private static final int WHISKERS0_COUNT = 7;

private static final int[] BUCKET_SIZES = new int[]{BG0_COUNT, BG1_COUNT, EARS0_COUNT, EARS1_COUNT, FACE0_COUNT,
FACE1_COUNT, EYES0_COUNT, NOSE0_COUNT, WHISKERS0_COUNT};

private static final String[] PATH_TEMPLATES;

static {
String postFix = ".png";
PATH_TEMPLATES = new String[]{
"bg0/" + DIGIT + postFix,
"bg1/" + DIGIT + postFix,
"ears0/" + DIGIT + postFix,
"ears1/" + DIGIT + postFix,
"face0/" + DIGIT + postFix,
"face1/" + DIGIT + postFix,
"eyes0/" + DIGIT + postFix,
"nose0/" + DIGIT + postFix,
"whiskers0/" + DIGIT + postFix
};

long numCombinations = getNumCombinations();
log.info("Number of combinations: 2^{} = {}", MathUtils.getLog2(numCombinations), numCombinations);
}

static int[] getBucketSizes() {
return BUCKET_SIZES;
}

static String[] getPathTemplates() {
return PATH_TEMPLATES;
}

static long getNumCombinations() {
long result = 1;
for (int bucketSize : BUCKET_SIZES) {
result *= bucketSize;
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.desktop.components.cathash;

import java.math.BigInteger;

public class BucketEncoder {
/**
* @param input A BigInteger input that is to be split up deterministically in buckets according to the bucketSizes array.
* @return buckets
*/
static int[] encode(BigInteger input, int[] bucketSizes) {
int currentBucket = 0;
int[] result = new int[bucketSizes.length];
while (currentBucket < bucketSizes.length) {
int bucketSize = bucketSizes[currentBucket];
BigInteger[] divisorReminder = input.divideAndRemainder(BigInteger.valueOf(bucketSize));
input = divisorReminder[0];
long reminder = divisorReminder[1].longValue();
result[currentBucket] = (int) Math.abs(reminder % bucketSize);
currentBucket++;
}
return result;
}

static String[] toPaths(int[] buckets, String[] pathTemplates) {
String[] paths = new String[buckets.length];
for (int facet = 0; facet < buckets.length; facet++) {
int bucketValue = buckets[facet];
paths[facet] = generatePath(pathTemplates[facet], bucketValue);
}
return paths;
}

private static String generatePath(String pathTemplate, int index) {
return pathTemplate.replaceAll(BucketConfig.DIGIT, String.format("%02d", index));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,10 @@
import java.util.concurrent.ConcurrentHashMap;

// Derived from https://github.com/neuhalje/android-robohash
// Number of combinations: 3 * 15 * 15 * 15 * 15 * 15 * 15 = 34171875 (2 ^ 25)
@Slf4j
public class CatHash {
private static final int SIZE = 300;
private static final int MAX_CACHE_SIZE = 10000;
private static final HandleFactory HANDLE_FACTORY = new HandleFactory();
private static final ConcurrentHashMap<ByteArray, Image> CACHE = new ConcurrentHashMap<>();

public static Image getImage(byte[] pubKeyHash) {
Expand All @@ -45,23 +44,13 @@ private static Image getImage(ByteArray pubKeyHash, boolean useCache) {
if (useCache && CACHE.containsKey(pubKeyHash)) {
return CACHE.get(pubKeyHash);
}
BigInteger bigInteger = new BigInteger(pubKeyHash.getBytes());
Configuration configuration = new Configuration();
VariableSizeHashing hashing = new VariableSizeHashing(configuration.getBucketSizes());
byte[] data = hashing.createBuckets(bigInteger);
Handle handle = HANDLE_FACTORY.calculateHandle(data);
Image image = imageForHandle(handle, configuration);
BigInteger input = new BigInteger(pubKeyHash.getBytes());
int[] buckets = BucketEncoder.encode(input, BucketConfig.getBucketSizes());
String[] paths = BucketEncoder.toPaths(buckets, BucketConfig.getPathTemplates());
Image image = ImageUtil.composeImage(paths, SIZE, SIZE);
if (useCache && CACHE.size() < MAX_CACHE_SIZE) {
CACHE.put(pubKeyHash, image);
}
return image;
}

private static Image imageForHandle(Handle handle, Configuration configuration) {
long ts = System.currentTimeMillis();
byte[] bucketValues = handle.bucketValues();
String[] paths = configuration.convertToFacetParts(bucketValues);
log.debug("Generated paths for CatHash image in {} ms", System.currentTimeMillis() - ts); // typically <1ms
return ImageUtil.composeImage(paths, configuration.width(), configuration.height());
}
}

This file was deleted.

This file was deleted.

Loading

0 comments on commit 793b50e

Please sign in to comment.