Merge branch 'master' into fork
This commit is contained in:
commit
e0e48f87eb
|
@ -0,0 +1,39 @@
|
||||||
|
package org.joinmastodon.android.api;
|
||||||
|
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class AvatarResizedImageRequestBody extends ResizedImageRequestBody{
|
||||||
|
public AvatarResizedImageRequestBody(Uri uri, ProgressListener progressListener) throws IOException{
|
||||||
|
super(uri, 0, progressListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int[] getTargetSize(int srcWidth, int srcHeight){
|
||||||
|
float factor=400f/Math.min(srcWidth, srcHeight);
|
||||||
|
return new int[]{Math.round(srcWidth*factor), Math.round(srcHeight*factor)};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean needResize(int srcWidth, int srcHeight){
|
||||||
|
return srcHeight>400 || srcWidth!=srcHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean needCrop(int srcWidth, int srcHeight){
|
||||||
|
return srcWidth!=srcHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Rect getCropBounds(int srcWidth, int srcHeight){
|
||||||
|
Rect rect=new Rect();
|
||||||
|
if(srcWidth>srcHeight){
|
||||||
|
rect.set(srcWidth/2-srcHeight/2, 0, srcWidth/2-srcHeight/2+srcHeight, srcHeight);
|
||||||
|
}else{
|
||||||
|
rect.set(0, srcHeight/2-srcWidth/2, srcWidth, srcHeight/2-srcWidth/2+srcWidth);
|
||||||
|
}
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import android.os.Build;
|
||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
|
|
||||||
import org.joinmastodon.android.MastodonApp;
|
import org.joinmastodon.android.MastodonApp;
|
||||||
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -30,62 +31,105 @@ public class ResizedImageRequestBody extends CountingRequestBody{
|
||||||
private File tempFile;
|
private File tempFile;
|
||||||
private Uri uri;
|
private Uri uri;
|
||||||
private String contentType;
|
private String contentType;
|
||||||
|
private int maxSize;
|
||||||
|
|
||||||
public ResizedImageRequestBody(Uri uri, int maxSize, ProgressListener progressListener) throws IOException{
|
public ResizedImageRequestBody(Uri uri, int maxSize, ProgressListener progressListener) throws IOException{
|
||||||
super(progressListener);
|
super(progressListener);
|
||||||
this.uri=uri;
|
this.uri=uri;
|
||||||
contentType=MastodonApp.context.getContentResolver().getType(uri);
|
this.maxSize=maxSize;
|
||||||
BitmapFactory.Options opts=new BitmapFactory.Options();
|
BitmapFactory.Options opts=new BitmapFactory.Options();
|
||||||
opts.inJustDecodeBounds=true;
|
opts.inJustDecodeBounds=true;
|
||||||
try(InputStream in=MastodonApp.context.getContentResolver().openInputStream(uri)){
|
if("file".equals(uri.getScheme())){
|
||||||
BitmapFactory.decodeStream(in, null, opts);
|
BitmapFactory.decodeFile(uri.getPath(), opts);
|
||||||
|
contentType=UiUtils.getFileMediaType(new File(uri.getPath())).type();
|
||||||
|
}else{
|
||||||
|
try(InputStream in=MastodonApp.context.getContentResolver().openInputStream(uri)){
|
||||||
|
BitmapFactory.decodeStream(in, null, opts);
|
||||||
|
}
|
||||||
|
contentType=MastodonApp.context.getContentResolver().getType(uri);
|
||||||
}
|
}
|
||||||
if(opts.outWidth*opts.outHeight>maxSize){
|
if(needResize(opts.outWidth, opts.outHeight) || needCrop(opts.outWidth, opts.outHeight)){
|
||||||
Bitmap bitmap;
|
Bitmap bitmap;
|
||||||
if(Build.VERSION.SDK_INT>=29){
|
if(Build.VERSION.SDK_INT>=28){
|
||||||
bitmap=ImageDecoder.decodeBitmap(ImageDecoder.createSource(MastodonApp.context.getContentResolver(), uri), (decoder, info, source)->{
|
ImageDecoder.Source source;
|
||||||
int targetWidth=Math.round((float)Math.sqrt((float)maxSize*((float)info.getSize().getWidth()/info.getSize().getHeight())));
|
if("file".equals(uri.getScheme())){
|
||||||
int targetHeight=Math.round((float)Math.sqrt((float)maxSize*((float)info.getSize().getHeight()/info.getSize().getWidth())));
|
source=ImageDecoder.createSource(new File(uri.getPath()));
|
||||||
|
}else{
|
||||||
|
source=ImageDecoder.createSource(MastodonApp.context.getContentResolver(), uri);
|
||||||
|
}
|
||||||
|
bitmap=ImageDecoder.decodeBitmap(source, (decoder, info, _source)->{
|
||||||
|
int[] size=getTargetSize(info.getSize().getWidth(), info.getSize().getHeight());
|
||||||
decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
|
decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
|
||||||
decoder.setTargetSize(targetWidth, targetHeight);
|
decoder.setTargetSize(size[0], size[1]);
|
||||||
|
// Breaks images in mysterious ways
|
||||||
|
// if(needCrop(size[0], size[1]))
|
||||||
|
// decoder.setCrop(getCropBounds(size[0], size[1]));
|
||||||
});
|
});
|
||||||
|
if(needCrop(bitmap.getWidth(), bitmap.getHeight())){
|
||||||
|
Rect crop=getCropBounds(bitmap.getWidth(), bitmap.getHeight());
|
||||||
|
bitmap=Bitmap.createBitmap(bitmap, crop.left, crop.top, crop.width(), crop.height());
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
int targetWidth=Math.round((float)Math.sqrt((float)maxSize*((float)opts.outWidth/opts.outHeight)));
|
int[] size=getTargetSize(opts.outWidth, opts.outHeight);
|
||||||
int targetHeight=Math.round((float)Math.sqrt((float)maxSize*((float)opts.outHeight/opts.outWidth)));
|
int targetWidth=size[0];
|
||||||
|
int targetHeight=size[1];
|
||||||
float factor=opts.outWidth/(float)targetWidth;
|
float factor=opts.outWidth/(float)targetWidth;
|
||||||
opts=new BitmapFactory.Options();
|
opts=new BitmapFactory.Options();
|
||||||
opts.inSampleSize=(int)factor;
|
opts.inSampleSize=(int)factor;
|
||||||
try(InputStream in=MastodonApp.context.getContentResolver().openInputStream(uri)){
|
if("file".equals(uri.getScheme())){
|
||||||
bitmap=BitmapFactory.decodeStream(in, null, opts);
|
bitmap=BitmapFactory.decodeFile(uri.getPath(), opts);
|
||||||
|
}else{
|
||||||
|
try(InputStream in=MastodonApp.context.getContentResolver().openInputStream(uri)){
|
||||||
|
bitmap=BitmapFactory.decodeStream(in, null, opts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(factor%1f!=0f){
|
boolean needCrop=needCrop(targetWidth, targetHeight);
|
||||||
Bitmap scaled=Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888);
|
if(factor%1f!=0f || needCrop){
|
||||||
new Canvas(scaled).drawBitmap(bitmap, null, new Rect(0, 0, targetWidth, targetHeight), new Paint(Paint.FILTER_BITMAP_FLAG));
|
Rect srcBounds=null;
|
||||||
|
Rect dstBounds;
|
||||||
|
if(needCrop){
|
||||||
|
Rect crop=getCropBounds(targetWidth, targetHeight);
|
||||||
|
dstBounds=new Rect(0, 0, crop.width(), crop.height());
|
||||||
|
srcBounds=new Rect(
|
||||||
|
Math.round(crop.left/(float)targetWidth*bitmap.getWidth()),
|
||||||
|
Math.round(crop.top/(float)targetHeight*bitmap.getHeight()),
|
||||||
|
Math.round(crop.right/(float)targetWidth*bitmap.getWidth()),
|
||||||
|
Math.round(crop.bottom/(float)targetHeight*bitmap.getHeight())
|
||||||
|
);
|
||||||
|
}else{
|
||||||
|
dstBounds=new Rect(0, 0, targetWidth, targetHeight);
|
||||||
|
}
|
||||||
|
Bitmap scaled=Bitmap.createBitmap(dstBounds.width(), dstBounds.height(), Bitmap.Config.ARGB_8888);
|
||||||
|
new Canvas(scaled).drawBitmap(bitmap, srcBounds, dstBounds, new Paint(Paint.FILTER_BITMAP_FLAG));
|
||||||
bitmap=scaled;
|
bitmap=scaled;
|
||||||
}
|
}
|
||||||
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
|
int orientation=0;
|
||||||
int rotation;
|
if("file".equals(uri.getScheme())){
|
||||||
|
ExifInterface exif=new ExifInterface(uri.getPath());
|
||||||
|
orientation=exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
||||||
|
}else if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
|
||||||
try(InputStream in=MastodonApp.context.getContentResolver().openInputStream(uri)){
|
try(InputStream in=MastodonApp.context.getContentResolver().openInputStream(uri)){
|
||||||
ExifInterface exif=new ExifInterface(in);
|
ExifInterface exif=new ExifInterface(in);
|
||||||
int orientation=exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
orientation=exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
||||||
rotation=switch(orientation){
|
|
||||||
case ExifInterface.ORIENTATION_ROTATE_90 -> 90;
|
|
||||||
case ExifInterface.ORIENTATION_ROTATE_180 -> 180;
|
|
||||||
case ExifInterface.ORIENTATION_ROTATE_270 -> 270;
|
|
||||||
default -> 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if(rotation!=0){
|
|
||||||
Matrix matrix=new Matrix();
|
|
||||||
matrix.setRotate(rotation);
|
|
||||||
bitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int rotation=switch(orientation){
|
||||||
|
case ExifInterface.ORIENTATION_ROTATE_90 -> 90;
|
||||||
|
case ExifInterface.ORIENTATION_ROTATE_180 -> 180;
|
||||||
|
case ExifInterface.ORIENTATION_ROTATE_270 -> 270;
|
||||||
|
default -> 0;
|
||||||
|
};
|
||||||
|
if(rotation!=0){
|
||||||
|
Matrix matrix=new Matrix();
|
||||||
|
matrix.setRotate(rotation);
|
||||||
|
bitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tempFile=new File(MastodonApp.context.getCacheDir(), "tmp_upload_image");
|
boolean isPNG="image/png".equals(contentType);
|
||||||
|
tempFile=File.createTempFile("mastodon_tmp_resized", null);
|
||||||
try(FileOutputStream out=new FileOutputStream(tempFile)){
|
try(FileOutputStream out=new FileOutputStream(tempFile)){
|
||||||
if("image/png".equals(contentType)){
|
if(isPNG){
|
||||||
bitmap.compress(Bitmap.CompressFormat.PNG, 0, out);
|
bitmap.compress(Bitmap.CompressFormat.PNG, 0, out);
|
||||||
}else{
|
}else{
|
||||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 97, out);
|
bitmap.compress(Bitmap.CompressFormat.JPEG, 97, out);
|
||||||
|
@ -94,9 +138,13 @@ public class ResizedImageRequestBody extends CountingRequestBody{
|
||||||
}
|
}
|
||||||
length=tempFile.length();
|
length=tempFile.length();
|
||||||
}else{
|
}else{
|
||||||
try(Cursor cursor=MastodonApp.context.getContentResolver().query(uri, new String[]{OpenableColumns.SIZE}, null, null, null)){
|
if("file".equals(uri.getScheme())){
|
||||||
cursor.moveToFirst();
|
length=new File(uri.getPath()).length();
|
||||||
length=cursor.getInt(0);
|
}else{
|
||||||
|
try(Cursor cursor=MastodonApp.context.getContentResolver().query(uri, new String[]{OpenableColumns.SIZE}, null, null, null)){
|
||||||
|
cursor.moveToFirst();
|
||||||
|
length=cursor.getInt(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,4 +173,22 @@ public class ResizedImageRequestBody extends CountingRequestBody{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected int[] getTargetSize(int srcWidth, int srcHeight){
|
||||||
|
int targetWidth=Math.round((float)Math.sqrt((float)maxSize*((float)srcWidth/srcHeight)));
|
||||||
|
int targetHeight=Math.round((float)Math.sqrt((float)maxSize*((float)srcHeight/srcWidth)));
|
||||||
|
return new int[]{targetWidth, targetHeight};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean needResize(int srcWidth, int srcHeight){
|
||||||
|
return srcWidth*srcHeight>maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean needCrop(int srcWidth, int srcHeight){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Rect getCropBounds(int srcWidth, int srcHeight){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,16 @@ package org.joinmastodon.android.api.requests.accounts;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.AvatarResizedImageRequestBody;
|
||||||
import org.joinmastodon.android.api.ContentUriRequestBody;
|
import org.joinmastodon.android.api.ContentUriRequestBody;
|
||||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
|
import org.joinmastodon.android.api.ResizedImageRequestBody;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.AccountField;
|
import org.joinmastodon.android.model.AccountField;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import okhttp3.MultipartBody;
|
import okhttp3.MultipartBody;
|
||||||
|
@ -39,21 +42,21 @@ public class UpdateAccountCredentials extends MastodonAPIRequest<Account>{
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RequestBody getRequestBody(){
|
public RequestBody getRequestBody() throws IOException{
|
||||||
MultipartBody.Builder bldr=new MultipartBody.Builder()
|
MultipartBody.Builder bldr=new MultipartBody.Builder()
|
||||||
.setType(MultipartBody.FORM)
|
.setType(MultipartBody.FORM)
|
||||||
.addFormDataPart("display_name", displayName)
|
.addFormDataPart("display_name", displayName)
|
||||||
.addFormDataPart("note", bio);
|
.addFormDataPart("note", bio);
|
||||||
|
|
||||||
if(avatar!=null){
|
if(avatar!=null){
|
||||||
bldr.addFormDataPart("avatar", UiUtils.getFileName(avatar), new ContentUriRequestBody(avatar, null));
|
bldr.addFormDataPart("avatar", UiUtils.getFileName(avatar), new AvatarResizedImageRequestBody(avatar, null));
|
||||||
}else if(avatarFile!=null){
|
}else if(avatarFile!=null){
|
||||||
bldr.addFormDataPart("avatar", avatarFile.getName(), RequestBody.create(UiUtils.getFileMediaType(avatarFile), avatarFile));
|
bldr.addFormDataPart("avatar", avatarFile.getName(), new AvatarResizedImageRequestBody(Uri.fromFile(avatarFile), null));
|
||||||
}
|
}
|
||||||
if(cover!=null){
|
if(cover!=null){
|
||||||
bldr.addFormDataPart("header", UiUtils.getFileName(cover), new ContentUriRequestBody(cover, null));
|
bldr.addFormDataPart("header", UiUtils.getFileName(cover), new ResizedImageRequestBody(cover, 1500*500, null));
|
||||||
}else if(coverFile!=null){
|
}else if(coverFile!=null){
|
||||||
bldr.addFormDataPart("header", coverFile.getName(), RequestBody.create(UiUtils.getFileMediaType(coverFile), coverFile));
|
bldr.addFormDataPart("header", coverFile.getName(), new ResizedImageRequestBody(Uri.fromFile(coverFile), 1500*500, null));
|
||||||
}
|
}
|
||||||
if(fields.isEmpty()){
|
if(fields.isEmpty()){
|
||||||
bldr.addFormDataPart("fields_attributes[0][name]", "").addFormDataPart("fields_attributes[0][value]", "");
|
bldr.addFormDataPart("fields_attributes[0][name]", "").addFormDataPart("fields_attributes[0][value]", "");
|
||||||
|
|
Loading…
Reference in New Issue