use JPEG as file format for avatar and compress to <9400 chars

This commit is contained in:
Daniel Gultsch 2017-12-15 20:49:48 +01:00
parent 0be41e0aab
commit bb6d5463fe
4 changed files with 69 additions and 97 deletions

View file

@ -61,7 +61,8 @@ public final class Config {
public static final int MINI_GRACE_PERIOD = 750; public static final int MINI_GRACE_PERIOD = 750;
public static final int AVATAR_SIZE = 192; public static final int AVATAR_SIZE = 192;
public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP; public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.JPEG;
public static final int AVATAR_CHAR_LIMIT = 9400;
public static final int IMAGE_SIZE = 1920; public static final int IMAGE_SIZE = 1920;
public static final Bitmap.CompressFormat IMAGE_FORMAT = Bitmap.CompressFormat.JPEG; public static final Bitmap.CompressFormat IMAGE_FORMAT = Bitmap.CompressFormat.JPEG;

View file

@ -535,29 +535,36 @@ public class FileBackend {
} }
public Avatar getPepAvatar(Uri image, int size, Bitmap.CompressFormat format) { public Avatar getPepAvatar(Uri image, int size, Bitmap.CompressFormat format) {
Bitmap bm = cropCenterSquare(image, size);
if (bm == null) {
return null;
}
return getPepAvatar(bm,format,100);
}
private Avatar getPepAvatar(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
try { try {
Avatar avatar = new Avatar();
Bitmap bm = cropCenterSquare(image, size);
if (bm == null) {
return null;
}
ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream(); ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream();
Base64OutputStream mBase64OutputStream = new Base64OutputStream( Base64OutputStream mBase64OutputStream = new Base64OutputStream(mByteArrayOutputStream, Base64.DEFAULT);
mByteArrayOutputStream, Base64.DEFAULT);
MessageDigest digest = MessageDigest.getInstance("SHA-1"); MessageDigest digest = MessageDigest.getInstance("SHA-1");
DigestOutputStream mDigestOutputStream = new DigestOutputStream( DigestOutputStream mDigestOutputStream = new DigestOutputStream(mBase64OutputStream, digest);
mBase64OutputStream, digest); if (!bitmap.compress(format, quality, mDigestOutputStream)) {
if (!bm.compress(format, 75, mDigestOutputStream)) {
return null; return null;
} }
mDigestOutputStream.flush(); mDigestOutputStream.flush();
mDigestOutputStream.close(); mDigestOutputStream.close();
long chars = mByteArrayOutputStream.size();
if (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.sha1sum = CryptoHelper.bytesToHex(digest.digest());
avatar.image = new String(mByteArrayOutputStream.toByteArray()); avatar.image = new String(mByteArrayOutputStream.toByteArray());
return avatar; return avatar;
} catch (NoSuchAlgorithmException e) { } catch (Exception e) {
return null;
} catch (IOException e) {
return null; return null;
} }
} }
@ -709,7 +716,11 @@ 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);
canvas.drawBitmap(source, null, targetRect, null); Paint p = new Paint();
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();
} }

View file

@ -6,10 +6,10 @@ import android.content.pm.PackageManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener; import android.view.View.OnLongClickListener;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
@ -20,7 +20,6 @@ import com.soundcloud.android.crop.Crop;
import java.io.File; import java.io.File;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.persistance.FileBackend;
@ -33,7 +32,6 @@ public class PublishProfilePictureActivity extends XmppActivity {
private static final int REQUEST_CHOOSE_FILE_AND_CROP = 0xac23; private static final int REQUEST_CHOOSE_FILE_AND_CROP = 0xac23;
private static final int REQUEST_CHOOSE_FILE = 0xac24; private static final int REQUEST_CHOOSE_FILE = 0xac24;
private ImageView avatar; private ImageView avatar;
private TextView accountTextView;
private TextView hintOrWarning; private TextView hintOrWarning;
private TextView secondaryHint; private TextView secondaryHint;
private Button cancelButton; private Button cancelButton;
@ -56,35 +54,27 @@ public class PublishProfilePictureActivity extends XmppActivity {
@Override @Override
public void success(Avatar object) { public void success(Avatar object) {
runOnUiThread(new Runnable() { runOnUiThread(() -> {
if (mInitialAccountSetup) {
@Override Intent intent = new Intent(getApplicationContext(),
public void run() { StartConversationActivity.class);
if (mInitialAccountSetup) { intent.putExtra("init", true);
Intent intent = new Intent(getApplicationContext(), startActivity(intent);
StartConversationActivity.class);
intent.putExtra("init", true);
startActivity(intent);
}
Toast.makeText(PublishProfilePictureActivity.this,
R.string.avatar_has_been_published,
Toast.LENGTH_SHORT).show();
finish();
} }
Toast.makeText(PublishProfilePictureActivity.this,
R.string.avatar_has_been_published,
Toast.LENGTH_SHORT).show();
finish();
}); });
} }
@Override @Override
public void error(final int errorCode, Avatar object) { public void error(final int errorCode, Avatar object) {
runOnUiThread(new Runnable() { runOnUiThread(() -> {
hintOrWarning.setText(errorCode);
@Override hintOrWarning.setTextColor(getWarningTextColor());
public void run() { publishButton.setText(R.string.publish);
hintOrWarning.setText(errorCode); enablePublishButton();
hintOrWarning.setTextColor(getWarningTextColor());
publishButton.setText(R.string.publish);
enablePublishButton();
}
}); });
} }
@ -98,48 +88,35 @@ public class PublishProfilePictureActivity extends XmppActivity {
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_publish_profile_picture); setContentView(R.layout.activity_publish_profile_picture);
this.avatar = (ImageView) findViewById(R.id.account_image); this.avatar = findViewById(R.id.account_image);
this.cancelButton = (Button) findViewById(R.id.cancel_button); this.cancelButton = findViewById(R.id.cancel_button);
this.publishButton = (Button) findViewById(R.id.publish_button); this.publishButton = findViewById(R.id.publish_button);
this.accountTextView = (TextView) findViewById(R.id.account); this.hintOrWarning = findViewById(R.id.hint_or_warning);
this.hintOrWarning = (TextView) findViewById(R.id.hint_or_warning); this.secondaryHint = findViewById(R.id.secondary_hint);
this.secondaryHint = (TextView) findViewById(R.id.secondary_hint); this.publishButton.setOnClickListener(v -> {
this.publishButton.setOnClickListener(new OnClickListener() { if (avatarUri != null) {
publishButton.setText(R.string.publishing);
@Override disablePublishButton();
public void onClick(View v) { xmppConnectionService.publishAvatar(account, avatarUri,
if (avatarUri != null) { avatarPublication);
publishButton.setText(R.string.publishing);
disablePublishButton();
xmppConnectionService.publishAvatar(account, avatarUri,
avatarPublication);
}
} }
}); });
this.cancelButton.setOnClickListener(new OnClickListener() { this.cancelButton.setOnClickListener(v -> {
if (mInitialAccountSetup) {
@Override Intent intent = new Intent(getApplicationContext(),
public void onClick(View v) { StartConversationActivity.class);
if (mInitialAccountSetup) { if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) {
Intent intent = new Intent(getApplicationContext(), intent.putExtra("init", true);
StartConversationActivity.class);
if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) {
intent.putExtra("init", true);
}
startActivity(intent);
} }
finish(); startActivity(intent);
} }
finish();
}); });
this.avatar.setOnClickListener(new OnClickListener() { this.avatar.setOnClickListener(v -> {
if (hasStoragePermission(REQUEST_CHOOSE_FILE)) {
@Override chooseAvatar(false);
public void onClick(View v) {
if (hasStoragePermission(REQUEST_CHOOSE_FILE)) {
chooseAvatar(false);
}
} }
}); });
this.defaultUri = PhoneHelper.getProfilePictureUri(getApplicationContext()); this.defaultUri = PhoneHelper.getProfilePictureUri(getApplicationContext());
} }
@ -153,7 +130,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
} }
@Override @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.length > 0)
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_CHOOSE_FILE_AND_CROP) { if (requestCode == REQUEST_CHOOSE_FILE_AND_CROP) {
@ -248,8 +225,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
this.secondaryHint.setVisibility(View.INVISIBLE); this.secondaryHint.setVisibility(View.INVISIBLE);
} }
if (!support) { if (!support) {
this.hintOrWarning this.hintOrWarning.setTextColor(getWarningTextColor());
.setTextColor(getWarningTextColor());
if (account.getStatus() == Account.State.ONLINE) { if (account.getStatus() == Account.State.ONLINE) {
this.hintOrWarning.setText(R.string.error_publish_avatar_no_server_support); this.hintOrWarning.setText(R.string.error_publish_avatar_no_server_support);
} else { } else {
@ -264,13 +240,6 @@ public class PublishProfilePictureActivity extends XmppActivity {
} else { } else {
loadImageIntoPreview(avatarUri); 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);
} }
} }
@ -296,8 +265,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
if (bm == null) { if (bm == null) {
disablePublishButton(); disablePublishButton();
this.hintOrWarning.setTextColor(getWarningTextColor()); this.hintOrWarning.setTextColor(getWarningTextColor());
this.hintOrWarning this.hintOrWarning.setText(R.string.error_publish_avatar_converting);
.setText(R.string.error_publish_avatar_converting);
return; return;
} }
this.avatar.setImageBitmap(bm); this.avatar.setImageBitmap(bm);

View file

@ -84,14 +84,6 @@
android:orientation="vertical" android:orientation="vertical"
android:paddingLeft="8dp" android:paddingLeft="8dp"
android:paddingRight="8dp" > android:paddingRight="8dp" >
<TextView
android:id="@+id/account"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/color_text_primary"
android:textSize="?attr/TextSizeHeadline" />
<TextView <TextView
android:id="@+id/hint_or_warning" android:id="@+id/hint_or_warning"
android:layout_width="wrap_content" android:layout_width="wrap_content"