Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bisq avatar improvements #1706

Merged
merged 7 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading