web-dev-qa-db-ja.com

イメージコンテキスト(CGContextRotateCTM)を回転すると、空白になります。どうして?

#define radians(degrees) (degrees * M_PI/180)

UIImage *rotate(UIImage *image) {
  CGSize size = image.size;;

  UIGraphicsBeginImageContext(size);
  CGContextRef context = UIGraphicsGetCurrentContext();

  // If this is commented out, image is returned as it is.
  CGContextRotateCTM (context, radians(90));

  [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
  UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();

  return newImage;
}

他に何か問題がありますか?アイデアのうち。

30
Gurpartap Singh

問題は、コンテキストが左上隅(0,0)を中心に回転していることです。左上隅を中心に90度回転すると、すべての描画がコンテキストの境界外で行われます。コンテキストの原点を中央に移動してから回転させるには、2ステップの変換が必要です。また、次のように、移動/回転したOriginを中心に画像を描画する必要があります。

CGContextTranslateCTM( context, 0.5f * size.width, 0.5f * size.height ) ;
CGContextRotateCTM( context, radians( 90 ) ) ;

[ image drawInRect:(CGRect){ { -size.width * 0.5f, -size.height * 0.5f }, size } ] ;

HTH

52
nielsbot

私はフォローしたコードを試します、それは機能します http://www.catamount.com/blog/1015/uiimage-extensions-for-cutting-scaling-and-rotating-uiimages/ から取得します

+ (UIImage *)rotateImage:(UIImage*)src byRadian:(CGFloat)radian
{
    // calculate the size of the rotated view's containing box for our drawing space
    //UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0, src.size.width, src.size.height)];
    //CGAffineTransform t = CGAffineTransformMakeRotation(radian);
    //rotatedViewBox.transform = t;
    //CGSize rotatedSize = rotatedViewBox.frame.size;
    CGRect rect = CGRectApplyAffineTransform(CGRectMake(0,0, src.size.width, src.size.height), CGAffineTransformMakeRotation(radian));
    CGSize rotatedSize = rect.size;

    // Create the bitmap context
    UIGraphicsBeginImageContext(rotatedSize);
    CGContextRef bitmap = UIGraphicsGetCurrentContext();

    // Move the Origin to the middle of the image so we will rotate and scale around the center.
    CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);

    //   // Rotate the image context
    CGContextRotateCTM(bitmap, radian);

    // Now, draw the rotated/scaled image into the context
    CGContextScaleCTM(bitmap, 1.0, -1.0);
    CGContextDrawImage(bitmap, CGRectMake(-src.size.width / 2, -src.size.height / 2, src.size.width, src.size.height), [src CGImage]);

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}
11
lbsweek

すべての原点とサイズを変更したくない場合は、中心を移動し、回転して、次のように中心を再びコーナーに変更します。

CGContextTranslateCTM( context, 0.5f * size.width, 0.5f * size.height ) ; CGContextRotateCTM( context, radians( 90 ) ) ; CGContextTranslateCTM( context, -0.5f * size.width, -0.5f * size.height ) ;

次に、通常は次のように描画します。

[image drawInRect:CGRectMake(0, 0, size.width, size.height)];

9

Nielsbotの答えを拡張して、次のスニペットを作成しました。これは、「コピー/貼り付けプログラミング」を防ぐために、コードスニペットではなく関数にすることが望ましいことに注意してください。まだ理解できていないので、自由に変更してください。

コードスニペット:

// <Draw in frame with orientation>
UIImage* imageToDrawRotated = <#image#>;
float rotationAngle = <#angle#>;
CGRect drawFrame = CGRectMake(<#CGFloat x#>, <#CGFloat y#>, <#CGFloat width#>, <#CGFloat height#>);
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), floor(drawFrame.Origin.x + drawFrame.size.width/2), floor(drawFrame.Origin.y + drawFrame.size.height/2));
CGContextRotateCTM(UIGraphicsGetCurrentContext(), rotationAngle);
[imageToDrawRotated drawInRect:CGRectMake(-floor(drawFrame.size.width/2), -floor(drawFrame.size.height/2), drawFrame.size.width, drawFrame.size.height)];
CGContextRotateCTM(UIGraphicsGetCurrentContext(), -rotationAngle);
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), -floor(drawFrame.Origin.x + drawFrame.size.width/2), -floor(drawFrame.Origin.y + drawFrame.size.height/2));
// </Draw in frame with orientation>

また、CGContextを以前の状態にリセットするより良い方法を歓迎します。

1
Timo

私は@lbsweekまでのソリューションが好きでしたが、変換のためだけにUIViewを割り当てるのが少し心配でしたが、代わりに以下を試しました

- (UIImage *)rotateImage:(UIImage *)sourceImage byDegrees:(float)degrees
{
    CGFloat radian = degrees * (M_PI/ 180);
    CGRect contextRect = CGRectMake(0, 0, sourceImage.size.width, sourceImage.size.height);
    float newSide = MAX([sourceImage size].width, [sourceImage size].height);
    CGSize newSize =  CGSizeMake(newSide, newSide);
    UIGraphicsBeginImageContext(newSize);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGPoint contextCenter = CGPointMake(CGRectGetMidX(contextRect), CGRectGetMidY(contextRect));
    CGContextTranslateCTM(ctx, contextCenter.x, contextCenter.y);
    CGContextRotateCTM(ctx, radian);
    CGContextTranslateCTM(ctx, -contextCenter.x, -contextCenter.y);
    [sourceImage drawInRect:contextRect];
    UIImage* rotatedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return rotatedImage;
}
1
anoop4real