More media layout optimizations

This commit is contained in:
Grishka 2023-03-27 04:04:16 +03:00
parent cf4604e0d8
commit 7b0a3f0f96
1 changed files with 45 additions and 39 deletions

View File

@ -32,28 +32,33 @@ public class PhotoLayoutHelper{
result.height=MAX_HEIGHT; result.height=MAX_HEIGHT;
result.width=MAX_WIDTH;//Math.round(att.getWidth()/(float)att.getHeight()*MAX_HEIGHT); result.width=MAX_WIDTH;//Math.round(att.getWidth()/(float)att.getHeight()*MAX_HEIGHT);
} }
result.tiles=new TiledLayoutResult.Tile[]{new TiledLayoutResult.Tile(1, 1, result.width, result.height, 0, 0)}; result.tiles=new TiledLayoutResult.Tile[]{new TiledLayoutResult.Tile(1, 1, 0, 0)};
return result; return result;
}else if(thumbs.size()==0){ }else if(thumbs.size()==0){
throw new IllegalArgumentException("Empty thumbs array"); throw new IllegalArgumentException("Empty thumbs array");
} }
String orients="";
ArrayList<Float> ratios=new ArrayList<>(); ArrayList<Float> ratios=new ArrayList<>();
int cnt=thumbs.size(); int cnt=thumbs.size();
boolean allAreWide=true, allAreSquare=true;
for(Attachment thumb : thumbs){ for(Attachment thumb : thumbs){
float ratio=thumb.getWidth()/(float) thumb.getHeight(); float ratio=thumb.getWidth()/(float) thumb.getHeight();
char orient=ratio>1.2 ? 'w' : (ratio<0.8 ? 'n' : 'q'); if(ratio<=1.2f){
orients+=orient; allAreWide=false;
if(ratio<0.8f)
allAreSquare=false;
}else{
allAreSquare=false;
}
ratios.add(ratio); ratios.add(ratio);
} }
float avgRatio=!ratios.isEmpty() ? sum(ratios)/ratios.size() : 1.0f; float avgRatio=!ratios.isEmpty() ? sum(ratios)/ratios.size() : 1.0f;
if(cnt==2){ if(cnt==2){
if(orients.equals("ww") && avgRatio>1.4*maxRatio && (ratios.get(1)-ratios.get(0))<0.2){ // two wide photos, one above the other if(allAreWide && avgRatio>1.4*maxRatio && (ratios.get(1)-ratios.get(0))<0.2){ // two wide photos, one above the other
float h=Math.max(Math.min(MAX_WIDTH/ratios.get(0), Math.min(MAX_WIDTH/ratios.get(1), (MAX_HEIGHT-GAP)/2.0f)), MIN_HEIGHT/2f); float h=Math.max(Math.min(MAX_WIDTH/ratios.get(0), Math.min(MAX_WIDTH/ratios.get(1), (MAX_HEIGHT-GAP)/2.0f)), MIN_HEIGHT/2f);
result.width=MAX_WIDTH; result.width=MAX_WIDTH;
@ -61,10 +66,10 @@ public class PhotoLayoutHelper{
result.columnSizes=new int[]{result.width}; result.columnSizes=new int[]{result.width};
result.rowSizes=new int[]{Math.round(h), Math.round(h)}; result.rowSizes=new int[]{Math.round(h), Math.round(h)};
result.tiles=new TiledLayoutResult.Tile[]{ result.tiles=new TiledLayoutResult.Tile[]{
new TiledLayoutResult.Tile(1, 1, MAX_WIDTH, h, 0, 0), new TiledLayoutResult.Tile(1, 1, 0, 0),
new TiledLayoutResult.Tile(1, 1, MAX_WIDTH, h, 0, 1) new TiledLayoutResult.Tile(1, 1, 0, 1)
}; };
}else if(orients.equals("ww") || orients.equals("qq")){ // next to each other, same ratio }else if(allAreWide || allAreSquare){ // next to each other, same ratio
float w=((MAX_WIDTH-GAP)/2); float w=((MAX_WIDTH-GAP)/2);
float h=Math.max(Math.min(w/ratios.get(0), Math.min(w/ratios.get(1), MAX_HEIGHT)), MIN_HEIGHT); float h=Math.max(Math.min(w/ratios.get(0), Math.min(w/ratios.get(1), MAX_HEIGHT)), MIN_HEIGHT);
@ -73,8 +78,8 @@ public class PhotoLayoutHelper{
result.columnSizes=new int[]{Math.round(w), MAX_WIDTH-Math.round(w)}; result.columnSizes=new int[]{Math.round(w), MAX_WIDTH-Math.round(w)};
result.rowSizes=new int[]{Math.round(h)}; result.rowSizes=new int[]{Math.round(h)};
result.tiles=new TiledLayoutResult.Tile[]{ result.tiles=new TiledLayoutResult.Tile[]{
new TiledLayoutResult.Tile(1, 1, w, h, 0, 0), new TiledLayoutResult.Tile(1, 1, 0, 0),
new TiledLayoutResult.Tile(1, 1, w, h, 1, 0) new TiledLayoutResult.Tile(1, 1, 1, 0)
}; };
}else{ // next to each other, different ratios }else{ // next to each other, different ratios
float w0=((MAX_WIDTH-GAP)/ratios.get(1)/(1/ratios.get(0)+1/ratios.get(1))); float w0=((MAX_WIDTH-GAP)/ratios.get(1)/(1/ratios.get(0)+1/ratios.get(1)));
@ -86,12 +91,12 @@ public class PhotoLayoutHelper{
result.width=Math.round(w0+w1+GAP); result.width=Math.round(w0+w1+GAP);
result.height=Math.round(h); result.height=Math.round(h);
result.tiles=new TiledLayoutResult.Tile[]{ result.tiles=new TiledLayoutResult.Tile[]{
new TiledLayoutResult.Tile(1, 1, w0, h, 0, 0), new TiledLayoutResult.Tile(1, 1, 0, 0),
new TiledLayoutResult.Tile(1, 1, w1, h, 1, 0) new TiledLayoutResult.Tile(1, 1, 1, 0)
}; };
} }
}else if(cnt==3){ }else if(cnt==3){
if((ratios.get(0) > 1.2 * maxRatio || avgRatio > 1.5 * maxRatio) || orients.equals("www")){ // 2nd and 3rd photos are on the next line if((ratios.get(0) > 1.2 * maxRatio || avgRatio > 1.5 * maxRatio) || allAreWide){ // 2nd and 3rd photos are on the next line
float hCover=Math.min(MAX_WIDTH/ratios.get(0), (MAX_HEIGHT-GAP)*0.66f); float hCover=Math.min(MAX_WIDTH/ratios.get(0), (MAX_HEIGHT-GAP)*0.66f);
float w2=((MAX_WIDTH-GAP)/2); float w2=((MAX_WIDTH-GAP)/2);
float h=Math.min(MAX_HEIGHT-hCover-GAP, Math.min(w2/ratios.get(1), w2/ratios.get(2))); float h=Math.min(MAX_HEIGHT-hCover-GAP, Math.min(w2/ratios.get(1), w2/ratios.get(2)));
@ -105,9 +110,9 @@ public class PhotoLayoutHelper{
result.columnSizes=new int[]{Math.round(w2), MAX_WIDTH-Math.round(w2)}; result.columnSizes=new int[]{Math.round(w2), MAX_WIDTH-Math.round(w2)};
result.rowSizes=new int[]{Math.round(hCover), Math.round(h)}; result.rowSizes=new int[]{Math.round(hCover), Math.round(h)};
result.tiles=new TiledLayoutResult.Tile[]{ result.tiles=new TiledLayoutResult.Tile[]{
new TiledLayoutResult.Tile(2, 1, MAX_WIDTH, hCover, 0, 0), new TiledLayoutResult.Tile(2, 1, 0, 0),
new TiledLayoutResult.Tile(1, 1, w2, h, 0, 1), new TiledLayoutResult.Tile(1, 1, 0, 1),
new TiledLayoutResult.Tile(1, 1, w2, h, 1, 1) new TiledLayoutResult.Tile(1, 1, 1, 1)
}; };
}else{ // 2nd and 3rd photos are on the right part }else{ // 2nd and 3rd photos are on the right part
float height=Math.min(MAX_HEIGHT, MAX_WIDTH*0.66f/avgRatio); float height=Math.min(MAX_HEIGHT, MAX_WIDTH*0.66f/avgRatio);
@ -120,13 +125,13 @@ public class PhotoLayoutHelper{
result.columnSizes=new int[]{Math.round(wCover), Math.round(w)}; result.columnSizes=new int[]{Math.round(wCover), Math.round(w)};
result.rowSizes=new int[]{Math.round(h0), Math.round(h1)}; result.rowSizes=new int[]{Math.round(h0), Math.round(h1)};
result.tiles=new TiledLayoutResult.Tile[]{ result.tiles=new TiledLayoutResult.Tile[]{
new TiledLayoutResult.Tile(1, 2, wCover, height, 0, 0), new TiledLayoutResult.Tile(1, 2, 0, 0),
new TiledLayoutResult.Tile(1, 1, w, h0, 1, 0), new TiledLayoutResult.Tile(1, 1, 1, 0),
new TiledLayoutResult.Tile(1, 1, w, h1, 1, 1) new TiledLayoutResult.Tile(1, 1, 1, 1)
}; };
} }
}else if(cnt==4){ }else if(cnt==4){
if((ratios.get(0) > 1.2 * maxRatio || avgRatio > 1.5 * maxRatio) || orients.equals("wwww")){ // 2nd, 3rd and 4th photos are on the next line if((ratios.get(0) > 1.2 * maxRatio || avgRatio > 1.5 * maxRatio) || allAreWide){ // 2nd, 3rd and 4th photos are on the next line
float hCover=Math.min(MAX_WIDTH/ratios.get(0), (MAX_HEIGHT-GAP)*0.66f); float hCover=Math.min(MAX_WIDTH/ratios.get(0), (MAX_HEIGHT-GAP)*0.66f);
float h=(MAX_WIDTH-2*GAP)/(ratios.get(1)+ratios.get(2)+ratios.get(3)); float h=(MAX_WIDTH-2*GAP)/(ratios.get(1)+ratios.get(2)+ratios.get(3));
float w0=h*ratios.get(1); float w0=h*ratios.get(1);
@ -143,10 +148,10 @@ public class PhotoLayoutHelper{
result.columnSizes=new int[]{Math.round(w0), Math.round(w1), MAX_WIDTH-Math.round(w0)-Math.round(w1)}; result.columnSizes=new int[]{Math.round(w0), Math.round(w1), MAX_WIDTH-Math.round(w0)-Math.round(w1)};
result.rowSizes=new int[]{Math.round(hCover), Math.round(h)}; result.rowSizes=new int[]{Math.round(hCover), Math.round(h)};
result.tiles=new TiledLayoutResult.Tile[]{ result.tiles=new TiledLayoutResult.Tile[]{
new TiledLayoutResult.Tile(3, 1, MAX_WIDTH, hCover, 0, 0), new TiledLayoutResult.Tile(3, 1, 0, 0),
new TiledLayoutResult.Tile(1, 1, w0, h, 0, 1), new TiledLayoutResult.Tile(1, 1, 0, 1),
new TiledLayoutResult.Tile(1, 1, w1, h, 1, 1), new TiledLayoutResult.Tile(1, 1, 1, 1),
new TiledLayoutResult.Tile(1, 1, w2, h, 2, 1), new TiledLayoutResult.Tile(1, 1, 2, 1),
}; };
}else{ // 2nd, 3rd and 4th photos are on the right part }else{ // 2nd, 3rd and 4th photos are on the right part
float height=Math.min(MAX_HEIGHT, MAX_WIDTH*0.66f/avgRatio); float height=Math.min(MAX_HEIGHT, MAX_WIDTH*0.66f/avgRatio);
@ -161,10 +166,10 @@ public class PhotoLayoutHelper{
result.columnSizes=new int[]{Math.round(wCover), Math.round(w)}; result.columnSizes=new int[]{Math.round(wCover), Math.round(w)};
result.rowSizes=new int[]{Math.round(h0), Math.round(h1), Math.round(h2)}; result.rowSizes=new int[]{Math.round(h0), Math.round(h1), Math.round(h2)};
result.tiles=new TiledLayoutResult.Tile[]{ result.tiles=new TiledLayoutResult.Tile[]{
new TiledLayoutResult.Tile(1, 3, wCover, height, 0, 0), new TiledLayoutResult.Tile(1, 3, 0, 0),
new TiledLayoutResult.Tile(1, 1, w, h0, 1, 0), new TiledLayoutResult.Tile(1, 1, 1, 0),
new TiledLayoutResult.Tile(1, 1, w, h1, 1, 1), new TiledLayoutResult.Tile(1, 1, 1, 1),
new TiledLayoutResult.Tile(1, 1, w, h2, 1, 2), new TiledLayoutResult.Tile(1, 1, 1, 2),
}; };
} }
}else{ }else{
@ -206,14 +211,15 @@ public class PhotoLayoutHelper{
} }
} }
// Looking for minimum difference between thumbs block height and MAX_HEIGHT (may probably be little over) // Looking for minimum difference between thumbs block height and maxHeight (may probably be little over)
final int realMaxHeight=Math.min(MAX_HEIGHT, MAX_WIDTH);
int[] optConf=null; int[] optConf=null;
float optDiff=0; float optDiff=0;
for(int[] conf : tries.keySet()){ for(int[] conf : tries.keySet()){
float[] heights=tries.get(conf); float[] heights=tries.get(conf);
float confH=GAP*(heights.length-1); float confH=GAP*(heights.length-1);
for(float h : heights) confH+=h; for(float h : heights) confH+=h;
float confDiff=Math.abs(confH-MAX_HEIGHT); float confDiff=Math.abs(confH-realMaxHeight);
if(conf.length>1){ if(conf.length>1){
if(conf[0]>conf[1] || conf.length>2 && conf[1]>conf[2]){ if(conf[0]>conf[1] || conf.length>2 && conf[1]>conf[2]){
confDiff*=1.1; confDiff*=1.1;
@ -252,7 +258,7 @@ public class PhotoLayoutHelper{
totalWidth+=Math.round(w); totalWidth+=Math.round(w);
if(j<lineThumbs.size()-1 && !gridLineOffsets.contains(totalWidth)) if(j<lineThumbs.size()-1 && !gridLineOffsets.contains(totalWidth))
gridLineOffsets.add(totalWidth); gridLineOffsets.add(totalWidth);
TiledLayoutResult.Tile tile=new TiledLayoutResult.Tile(1, 1, w, lineHeight, 0, i); TiledLayoutResult.Tile tile=new TiledLayoutResult.Tile(1, 1, 0, i, Math.round(w));
result.tiles[k]=tile; result.tiles[k]=tile;
row.add(tile); row.add(tile);
k++; k++;
@ -318,19 +324,19 @@ public class PhotoLayoutHelper{
} }
public static class Tile{ public static class Tile{
public int colSpan, rowSpan, width, height, startCol, startRow; public int colSpan, rowSpan, startCol, startRow;
public int width;
public Tile(int colSpan, int rowSpan, int width, int height, int startCol, int startRow){ public Tile(int colSpan, int rowSpan, int startCol, int startRow){
this.colSpan=colSpan; this.colSpan=colSpan;
this.rowSpan=rowSpan; this.rowSpan=rowSpan;
this.width=width;
this.height=height;
this.startCol=startCol; this.startCol=startCol;
this.startRow=startRow; this.startRow=startRow;
} }
public Tile(int colSpan, int rowSpan, float width, float height, int startCol, int startRow){ public Tile(int colSpan, int rowSpan, int startCol, int startRow, int width){
this(colSpan, rowSpan, Math.round(width), Math.round(height), startCol, startRow); this(colSpan, rowSpan, startCol, startRow);
this.width=width;
} }
@Override @Override
@ -338,8 +344,8 @@ public class PhotoLayoutHelper{
return "Tile{"+ return "Tile{"+
"colSpan="+colSpan+ "colSpan="+colSpan+
", rowSpan="+rowSpan+ ", rowSpan="+rowSpan+
", width="+width+ ", startCol="+startCol+
", height="+height+ ", startRow="+startRow+
'}'; '}';
} }
} }