2012年4月16日月曜日

tiling routine

縦横比の異なる複数の画像を、なるべく効率的に隙間なく並べる、というか最終的にはアスペクト比を維持したまま画面からはみ出さないようリサイズするので、複数の画像を矩形に組み上げるルーチン、かな。をとりあえず動くようにしてみた。NSNumberが直接演算できないとか、配列の添字がobjectAtIndex:ってのに未だに慣れず、コードを綺麗に書けない。マクロもどうかなーってくらいの微妙な冗長さ。どうするのがいいのかな。

配列contArrにはtumblrAPIから返ってきたresponse.postsの中身が入ってるという前提で、以下のとおり:

1.photoの場合はtumblrAPIからoriginal_sizeのurlが配列で返ってくるので、高速列挙にぶちこんでサイズ、比率、自身のUIImageオブジェクトを配列に格納する。1postに画像が複数ある場合は当然複数入る。
2.画像を取り出して、画面の縦横比よりも縦長で且つまだ次の画像があれば、その二つが隙間なく画面の幅に収まるよう横に並べられる共通の高さを取得(newh)する。
3.それでもまだ画面の縦横比より縦長で且つまだ次の画像があれば、先のものと合わせて隙間なく画面の幅に収まるよう横に並べられる共通の高さを取得(newh)する。これは全部の画像をくっつけて縦長じゃなくなるまで続ける。”縦長”の定義は、画面の比率以外にも、”正方形より”縦長、”横2:縦1より”縦長などが考えられるが、現時点では画面比で。
4.既に同じように生成した画像があれば(配列に画像を残して横長になった場合は)、まずその画像をdrawAtPointしておく。
5.2~3で処理した画像をdrawInRectする。
6.複数画像を1つの画像に合体(getImage)する。
7.1postに画像が1つ、または画像が横長、または縦長でも配列最後の画像であれば、単に画面幅に合わせてリサイズし、既に同じように生成した画像があれば(配列に画像を残して横長になった場合は)、まずその画像をdrawAtPointしてからdrawInRectしてgetImageする。
8.最後に1post分の画像としてUIImageViewに貼ってアスペクト比を維持したまま画面からはみ出さないようリサイズ。

#define nwf(x) [NSNumber numberWithFloat:x]

- (void)makeTimeLine{
 UIScreen *uis=[UIScreen mainScreen];
 float sw=[uis bounds].size.width,sh=[uis bounds].size.height,sr=sw/sh;
 int i=0;
 for(id cont in contArr){
  if([cont isKindOfClass:[NSArray class]]){
   UIImage *mixedimg;
   NSMutableArray
   *imgSizeArr=[[NSMutableArray alloc]initWithCapacity:0],*imgRatioArr=[[NSMutableArray alloc]initWithCapacity:0],
   *imgSetArr=[[NSMutableArray alloc]initWithCapacity:0];
   for(id parts in cont){ //1.高速列挙にぶちこむ
    UIImage *img=[[UIImage alloc]initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:parts]]];
    [imgSizeArr addObject:nwf(img.size.width)];[imgSizeArr addObject:nwf(img.size.height)];
    [imgRatioArr addObject:nwf(img.size.width/img.size.height)];
    [imgSetArr addObject:img];
   }
   int curw=0,curh=0,k=0;
   for(int j=0;j<[imgSetArr count];j++){
    if([[imgRatioArr objectAtIndex:j]floatValue]<sr&&[imgSetArr count]>j+1){ //2.画像の比率チェック
     int over3=4;
     float firstw=[[imgSizeArr objectAtIndex:j*2]floatValue],firsth=[[imgSizeArr objectAtIndex:j*2+1]floatValue],firstr=firsth/firstw;
     float nextw=[[imgSizeArr objectAtIndex:j*2+2]floatValue],nexth=[[imgSizeArr objectAtIndex:j*2+3]floatValue];
     float newh=firstr*((sw*nexth)/(nextw*firstr+nexth));
     while (sw/newh<sr&&[imgSetArr count]>j+over3/2) { //3.縦長の限りずっと
      nextw=[[imgSizeArr objectAtIndex:j*2+over3]floatValue],nexth=[[imgSizeArr objectAtIndex:j*2+over3+1]floatValue];
      newh=(newh/sw)*((sw*nexth)/(nextw*(newh/sw)+nexth));
      over3+=2;
     }
     j+=1+(over3/2-2);
     UIGraphicsBeginImageContext(CGSizeMake(sw,curh+newh));
     if(mixedimg){[mixedimg drawAtPoint:CGPointMake(0, 0)];} //4.既に合体画像がある場合
     while(k>j+1){ //5.複数画像を描画
      float neww=newh*[[imgSetArr objectAtIndex:k]size].width/[[imgSetArr objectAtIndex:k]size].height;
      [[imgSetArr objectAtIndex:k]drawInRect:(CGRectMake(curw, curh,neww,newh))];
      curw+=neww;k++;
     }
     curh+=newh;curw=0;
     mixedimg=UIGraphicsGetImageFromCurrentImageContext(); //6.複数画像を1つの画像に
     UIGraphicsEndImageContext();
     }else{ //7.画像が1つの場合は単に画面幅に合わせてリサイズ
      UIGraphicsBeginImageContext(CGSizeMake(sw,curh+sw*[[imgSetArr objectAtIndex:j]size].height/[[imgSetArr objectAtIndex:j]size].width));
      if(mixedimg){[mixedimg drawAtPoint:CGPointMake(0, 0)];}
      float newh=sw*[[imgSetArr objectAtIndex:j]size].height/[[imgSetArr objectAtIndex:j]size].width;
      [[imgSetArr objectAtIndex:j]drawInRect:(CGRectMake(0, curh, sw, newh))];
      mixedimg=UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();
      curh+=sw*[[imgSetArr objectAtIndex:j]size].height/[[imgSetArr objectAtIndex:j]size].width;
     }
    }
   UIImageView *imgset=[[UIImageView alloc]initWithImage:mixedimg]; //8.1post分の画像を生成
   if(mixedimg.size.width/mixedimg.size.height<sw/sh) [imgset setFrame:CGRectMake(0, 0, sh*mixedimg.size.width/mixedimg.size.height, sh)];
   else [imgset setFrame:CGRectMake(0, 0, sw, sw*mixedimg.size.height/mixedimg.size.width)];
   [self.view addSubview:imgset];
   }else{//NON-photo
    NSLog(@"%d / %@",i,cont);
   }
  i++;
 }
}

できた。
横に並べる場合の比率なんかはこれからテストする。
というか、複数画像の場合は別メソッドに抜き出して渡したほうがいいな。あとでやろう。

昨晩は日本橋の一蘭。うまく隙間時間に入れて待たずに食べれた。帰るときは結構な行列だった。今月10杯目。ペースが遅い。

0 件のコメント:

コメントを投稿