aboutsummaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
authorChristian Schneppe <christian@pix-art.de>2017-12-23 23:21:49 +0100
committerChristian Schneppe <christian@pix-art.de>2017-12-23 23:21:49 +0100
commit1cee1ffcfd48e66446b7ac863fb1048c0d57b4d9 (patch)
tree5d7a8fe8f3b036e7f435b73c437f61f8cf3bd5da /src/main
parent94f298de6cf4eeb0acc4e921be7117125f4aebe2 (diff)
use JPEG as file format for avatar and compress to <9400 chars and
create avatar in background thread
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/de/pixart/messenger/Config.java1
-rw-r--r--src/main/java/de/pixart/messenger/persistance/FileBackend.java80
-rw-r--r--src/main/java/de/pixart/messenger/services/XmppConnectionService.java37
-rw-r--r--src/main/java/de/pixart/messenger/ui/PublishProfilePictureActivity.java28
-rw-r--r--src/main/res/layout/activity_publish_profile_picture.xml8
5 files changed, 82 insertions, 72 deletions
diff --git a/src/main/java/de/pixart/messenger/Config.java b/src/main/java/de/pixart/messenger/Config.java
index 7715ed665..0604b0dda 100644
--- a/src/main/java/de/pixart/messenger/Config.java
+++ b/src/main/java/de/pixart/messenger/Config.java
@@ -72,6 +72,7 @@ public final class Config {
public static final int AVATAR_SIZE = 480;
public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.JPEG;
+ public static final int AVATAR_CHAR_LIMIT = 9400;
public static final Bitmap.CompressFormat IMAGE_FORMAT = Bitmap.CompressFormat.JPEG;
public static final int IMAGE_QUALITY = 75;
diff --git a/src/main/java/de/pixart/messenger/persistance/FileBackend.java b/src/main/java/de/pixart/messenger/persistance/FileBackend.java
index 1d143cc53..b71c10cf5 100644
--- a/src/main/java/de/pixart/messenger/persistance/FileBackend.java
+++ b/src/main/java/de/pixart/messenger/persistance/FileBackend.java
@@ -10,6 +10,7 @@ import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
@@ -512,16 +513,20 @@ public class FileBackend {
private void drawOverlay(Bitmap bitmap, int resource, float factor) {
Bitmap overlay = BitmapFactory.decodeResource(mXmppConnectionService.getResources(), resource);
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;
Log.d(Config.LOGTAG, "target size overlay: " + targetSize + " overlay bitmap size was " + overlay.getHeight());
float left = (canvas.getWidth() - targetSize) / 2.0f;
float top = (canvas.getHeight() - targetSize) / 2.0f;
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) {
@@ -583,30 +588,63 @@ public class FileBackend {
}
+ 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;
+ }
+
public Avatar getPepAvatar(Uri image, int size, Bitmap.CompressFormat format) {
+ Bitmap bm = cropCenterSquare(image, size);
+ if (bm == 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);
+ }
+
+ private Avatar getPepAvatar(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
try {
- Avatar avatar = new Avatar();
- Bitmap bm = cropCenterSquare(image, size);
- if (bm == null) {
- return null;
- }
ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream();
- Base64OutputStream mBase64OutputStream = new Base64OutputStream(
- mByteArrayOutputStream, Base64.DEFAULT);
+ Base64OutputStream mBase64OutputStream = new Base64OutputStream(mByteArrayOutputStream, Base64.DEFAULT);
MessageDigest digest = MessageDigest.getInstance("SHA-1");
- DigestOutputStream mDigestOutputStream = new DigestOutputStream(
- mBase64OutputStream, digest);
- if (!bm.compress(format, 75, mDigestOutputStream)) {
+ DigestOutputStream mDigestOutputStream = new DigestOutputStream(mBase64OutputStream, digest);
+ if (!bitmap.compress(format, quality, mDigestOutputStream)) {
return null;
}
mDigestOutputStream.flush();
mDigestOutputStream.close();
+ long chars = mByteArrayOutputStream.size();
+ if (format != Bitmap.CompressFormat.PNG && quality >= 50 && chars >= Config.AVATAR_CHAR_LIMIT) {
+ int q = quality - 2;
+ Log.d(Config.LOGTAG, "avatar char length was " + chars + " reducing quality to " + q);
+ return getPepAvatar(bitmap, format, q);
+ }
+ Log.d(Config.LOGTAG, "settled on char length " + chars + " with quality=" + quality);
+ final Avatar avatar = new Avatar();
avatar.sha1sum = CryptoHelper.bytesToHex(digest.digest());
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;
- } catch (NoSuchAlgorithmException e) {
- return null;
- } catch (IOException e) {
+ } catch (Exception e) {
return null;
}
}
@@ -758,7 +796,7 @@ public class FileBackend {
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(dest);
- canvas.drawBitmap(source, null, targetRect, null);
+ canvas.drawBitmap(source, null, targetRect, createAntiAliasingPaint());
if (source.isRecycled()) {
source.recycle();
}
@@ -786,8 +824,8 @@ public class FileBackend {
Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
- canvas.drawBitmap(input, null, target, null);
- if (input != null && !input.isRecycled()) {
+ canvas.drawBitmap(input, null, target, createAntiAliasingPaint());
+ if (!input.isRecycled()) {
input.recycle();
}
return output;
diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
index 7b2231cc3..9adaad692 100644
--- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
+++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
@@ -2997,28 +2997,21 @@ public class XmppConnectionService extends Service {
}
}
- public void publishAvatar(Account account, Uri image, UiCallback<Avatar> callback) {
- final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
- final int size = Config.AVATAR_SIZE;
- final Avatar avatar = getFileBackend().getPepAvatar(image, size, format);
- 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)) {
- callback.error(R.string.error_saving_avatar, avatar);
- return;
- }
- publishAvatar(account, avatar, callback);
- } else {
- callback.error(R.string.error_publish_avatar_converting, null);
- }
+ public void publishAvatar(final Account account, final Uri image, final UiCallback<Avatar> callback) {
+ new Thread(() -> {
+ final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
+ final int size = Config.AVATAR_SIZE;
+ final Avatar avatar = getFileBackend().getPepAvatar(image, size, format);
+ if (avatar != null) {
+ if (!getFileBackend().save(avatar)) {
+ callback.error(R.string.error_saving_avatar, avatar);
+ return;
+ }
+ publishAvatar(account, avatar, callback);
+ } else {
+ callback.error(R.string.error_publish_avatar_converting, null);
+ }
+ }).start();
}
public void publishAvatar(Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
diff --git a/src/main/java/de/pixart/messenger/ui/PublishProfilePictureActivity.java b/src/main/java/de/pixart/messenger/ui/PublishProfilePictureActivity.java
index e79a5026d..707d7cfc8 100644
--- a/src/main/java/de/pixart/messenger/ui/PublishProfilePictureActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/PublishProfilePictureActivity.java
@@ -6,12 +6,12 @@ import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.Button;
import android.widget.ImageView;
@@ -98,18 +98,13 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
this.avatar = findViewById(R.id.account_image);
this.cancelButton = findViewById(R.id.cancel_button);
this.publishButton = findViewById(R.id.publish_button);
- this.accountTextView = findViewById(R.id.account);
this.hintOrWarning = findViewById(R.id.hint_or_warning);
this.secondaryHint = findViewById(R.id.secondary_hint);
- this.publishButton.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- if (avatarUri != null) {
- publishing = true;
- togglePublishButton(false, R.string.publishing);
- xmppConnectionService.publishAvatar(account, avatarUri, avatarPublication);
- }
+ this.publishButton.setOnClickListener(v -> {
+ if (avatarUri != null) {
+ publishing = true;
+ togglePublishButton(false,R.string.publishing);
+ xmppConnectionService.publishAvatar(account, avatarUri, avatarPublication);
}
});
this.cancelButton.setOnClickListener(v -> {
@@ -127,7 +122,6 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
if (hasStoragePermission(REQUEST_CHOOSE_FILE)) {
chooseAvatar(false);
}
-
});
this.defaultUri = PhoneHelper.getProfilePictureUri(getApplicationContext());
}
@@ -141,7 +135,7 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
}
@Override
- public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
+ public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
if (grantResults.length > 0)
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_CHOOSE_FILE_AND_CROP) {
@@ -238,14 +232,6 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
} else {
loadImageIntoPreview(avatarUri);
}
- String account;
- if (Config.DOMAIN_LOCK != null) {
- account = this.account.getJid().getLocalpart();
- } else {
- account = this.account.getJid().toBareJid().toString();
- }
- this.accountTextView.setText(account);
-
}
@Override
diff --git a/src/main/res/layout/activity_publish_profile_picture.xml b/src/main/res/layout/activity_publish_profile_picture.xml
index 3c7971b1e..922d1f8f3 100644
--- a/src/main/res/layout/activity_publish_profile_picture.xml
+++ b/src/main/res/layout/activity_publish_profile_picture.xml
@@ -88,14 +88,6 @@
android:textAlignment="center" />
<TextView
- android:id="@+id/account"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeHeadline"
- android:visibility="gone" />
-
- <TextView
android:id="@+id/hint_or_warning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"