create avatar in background thread

This commit is contained in:
Daniel Gultsch 2017-12-16 14:22:57 +01:00
parent 9b95f1102c
commit c58fcb1dc6
2 changed files with 100 additions and 79 deletions

View file

@ -8,6 +8,7 @@ import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.RectF; import android.graphics.RectF;
@ -465,16 +466,20 @@ public class FileBackend {
private void drawOverlay(Bitmap bitmap, int resource, float factor) { private void drawOverlay(Bitmap bitmap, int resource, float factor) {
Bitmap overlay = BitmapFactory.decodeResource(mXmppConnectionService.getResources(), resource); Bitmap overlay = BitmapFactory.decodeResource(mXmppConnectionService.getResources(), resource);
Canvas canvas = new Canvas(bitmap); Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
float targetSize = Math.min(canvas.getWidth(), canvas.getHeight()) * factor; float targetSize = Math.min(canvas.getWidth(), canvas.getHeight()) * factor;
Log.d(Config.LOGTAG, "target size overlay: " + targetSize + " overlay bitmap size was " + overlay.getHeight()); Log.d(Config.LOGTAG, "target size overlay: " + targetSize + " overlay bitmap size was " + overlay.getHeight());
float left = (canvas.getWidth() - targetSize) / 2.0f; float left = (canvas.getWidth() - targetSize) / 2.0f;
float top = (canvas.getHeight() - targetSize) / 2.0f; float top = (canvas.getHeight() - targetSize) / 2.0f;
RectF dst = new RectF(left, top, left + targetSize - 1, top + targetSize - 1); RectF dst = new RectF(left, top, left + targetSize - 1, top + targetSize - 1);
canvas.drawBitmap(overlay,null,dst,paint); canvas.drawBitmap(overlay, null, dst, createAntiAliasingPaint());
}
private static Paint createAntiAliasingPaint() {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
return paint;
} }
private Bitmap getVideoPreview(File file, int size) { private Bitmap getVideoPreview(File file, int size) {
@ -539,9 +544,26 @@ public class FileBackend {
if (bm == null) { if (bm == null) {
return null; return null;
} }
if (hasAlpha(bm)) {
Log.d(Config.LOGTAG,"alpha in avatar detected; uploading as PNG");
bm.recycle();
bm = cropCenterSquare(image, 96);
return getPepAvatar(bm, Bitmap.CompressFormat.PNG, 100);
}
return getPepAvatar(bm, format, 100); return getPepAvatar(bm, format, 100);
} }
private static boolean hasAlpha(final Bitmap bitmap) {
for(int x = 0; x < bitmap.getWidth(); ++x) {
for(int y = 0; y < bitmap.getWidth(); ++y) {
if (Color.alpha(bitmap.getPixel(x,y)) < 255) {
return true;
}
}
}
return false;
}
private Avatar getPepAvatar(Bitmap bitmap, Bitmap.CompressFormat format, int quality) { private Avatar getPepAvatar(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
try { try {
ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream(); ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream();
@ -554,7 +576,7 @@ public class FileBackend {
mDigestOutputStream.flush(); mDigestOutputStream.flush();
mDigestOutputStream.close(); mDigestOutputStream.close();
long chars = mByteArrayOutputStream.size(); long chars = mByteArrayOutputStream.size();
if (quality >= 50 && chars >= Config.AVATAR_CHAR_LIMIT) { if (format != Bitmap.CompressFormat.PNG && quality >= 50 && chars >= Config.AVATAR_CHAR_LIMIT) {
int q = quality - 2; int q = quality - 2;
Log.d(Config.LOGTAG, "avatar char length was " + chars + " reducing quality to " + q); Log.d(Config.LOGTAG, "avatar char length was " + chars + " reducing quality to " + q);
return getPepAvatar(bitmap, format, q); return getPepAvatar(bitmap, format, q);
@ -563,6 +585,15 @@ public class FileBackend {
final Avatar avatar = new Avatar(); final Avatar avatar = new Avatar();
avatar.sha1sum = CryptoHelper.bytesToHex(digest.digest()); avatar.sha1sum = CryptoHelper.bytesToHex(digest.digest());
avatar.image = new String(mByteArrayOutputStream.toByteArray()); avatar.image = new String(mByteArrayOutputStream.toByteArray());
if (format.equals(Bitmap.CompressFormat.WEBP)) {
avatar.type = "image/webp";
} else if (format.equals(Bitmap.CompressFormat.JPEG)) {
avatar.type = "image/jpeg";
} else if (format.equals(Bitmap.CompressFormat.PNG)) {
avatar.type = "image/png";
}
avatar.width = bitmap.getWidth();
avatar.height = bitmap.getHeight();
return avatar; return avatar;
} catch (Exception e) { } catch (Exception e) {
return null; return null;
@ -716,11 +747,7 @@ public class FileBackend {
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight); RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888); Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(dest); Canvas canvas = new Canvas(dest);
Paint p = new Paint(); canvas.drawBitmap(source, null, targetRect, createAntiAliasingPaint());
p.setAntiAlias(true);
p.setFilterBitmap(true);
p.setDither(true);
canvas.drawBitmap(source, null, targetRect, p);
if (source.isRecycled()) { if (source.isRecycled()) {
source.recycle(); source.recycle();
} }
@ -748,8 +775,8 @@ public class FileBackend {
Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output); Canvas canvas = new Canvas(output);
canvas.drawBitmap(input, null, target, null); canvas.drawBitmap(input, null, target, createAntiAliasingPaint());
if (input != null && !input.isRecycled()) { if (!input.isRecycled()) {
input.recycle(); input.recycle();
} }
return output; return output;

View file

@ -2808,20 +2808,12 @@ public class XmppConnectionService extends Service {
} }
} }
public void publishAvatar(Account account, Uri image, UiCallback<Avatar> callback) { public void publishAvatar(final Account account, final Uri image, final UiCallback<Avatar> callback) {
new Thread(() -> {
final Bitmap.CompressFormat format = Config.AVATAR_FORMAT; final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
final int size = Config.AVATAR_SIZE; final int size = Config.AVATAR_SIZE;
final Avatar avatar = getFileBackend().getPepAvatar(image, size, format); final Avatar avatar = getFileBackend().getPepAvatar(image, size, format);
if (avatar != null) { if (avatar != null) {
avatar.height = size;
avatar.width = size;
if (format.equals(Bitmap.CompressFormat.WEBP)) {
avatar.type = "image/webp";
} else if (format.equals(Bitmap.CompressFormat.JPEG)) {
avatar.type = "image/jpeg";
} else if (format.equals(Bitmap.CompressFormat.PNG)) {
avatar.type = "image/png";
}
if (!getFileBackend().save(avatar)) { if (!getFileBackend().save(avatar)) {
callback.error(R.string.error_saving_avatar, avatar); callback.error(R.string.error_saving_avatar, avatar);
return; return;
@ -2830,6 +2822,8 @@ public class XmppConnectionService extends Service {
} else { } else {
callback.error(R.string.error_publish_avatar_converting, null); callback.error(R.string.error_publish_avatar_converting, null);
} }
}).start();
} }
public void publishAvatar(Account account, final Avatar avatar, final UiCallback<Avatar> callback) { public void publishAvatar(Account account, final Avatar avatar, final UiCallback<Avatar> callback) {