34

これが私がこれまでに成し遂げたところです。カメラからキャプチャしたUIImageを使用しており、横向きのときに中央の正方形をトリミングできます。何らかの理由で、これは期待どおりにポートレートモードに変換されません。参考までに、コードとログを投稿します。

コード:

CGRect squareRect = CGRectMake(offsetX, offsetY, newWidth, newHeight);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], squareRect);
image = [UIImage imageWithCGImage:imageRef scale:1 orientation:image.imageOrientation];

縦向きの結果(正方形ではない):

original image size: {1536, 2048}, with orientation: 3
squareRect: {{0, 256}, {1536, 1536}}
new image size: {1280, 1536}, with orientation: 3 <--- not expected

風景の結果(正方形):

original image size: {2048, 1536}, with orientation: 1
squareRect: {{256, 0}, {1536, 1536}}
new image size: {1536, 1536}, with orientation: 1

これはCGImageCreateWithImageInRect()内のバグですか、それともここで何かが足りませんか?

4

19 に答える 19

28

ここが完璧な解決策になると思います!のサイズ
に基づいて画像をトリミングすることはお勧めできません。画像の解像度(サイズ)が非常に大きいと、奇妙に見えます。次のコードは、の比率に従って画像をトリミングします。@BlackRiderの回答 から改善されました。toSize
toSize

- (UIImage *)imageByCroppingImage:(UIImage *)image toSize:(CGSize)size
{
    double newCropWidth, newCropHeight;

    //=== To crop more efficently =====//
    if(image.size.width < image.size.height){
         if (image.size.width < size.width) {
                 newCropWidth = size.width;
          }
          else {
                 newCropWidth = image.size.width;
          }
          newCropHeight = (newCropWidth * size.height)/size.width;
    } else {
          if (image.size.height < size.height) {
                newCropHeight = size.height;
          }
          else {
                newCropHeight = image.size.height;
          }
          newCropWidth = (newCropHeight * size.width)/size.height;
    }
    //==============================//

    double x = image.size.width/2.0 - newCropWidth/2.0;
    double y = image.size.height/2.0 - newCropHeight/2.0;

    CGRect cropRect = CGRectMake(x, y, newCropWidth, newCropHeight);
    CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);

    UIImage *cropped = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);

    return cropped;
}
于 2015-05-26T07:22:18.613 に答える
25

これは、さまざまな方向で機能します。縦向きと横向きの両方が正しく機能します。

- (UIImage *)imageByCroppingImage:(UIImage *)image toSize:(CGSize)size
{
    // not equivalent to image.size (which depends on the imageOrientation)!
    double refWidth = CGImageGetWidth(image.CGImage);
    double refHeight = CGImageGetHeight(image.CGImage);

    double x = (refWidth - size.width) / 2.0;
    double y = (refHeight - size.height) / 2.0;

    CGRect cropRect = CGRectMake(x, y, size.height, size.width);
    CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);

    UIImage *cropped = [UIImage imageWithCGImage:imageRef scale:0.0 orientation:self.imageOrientation];
    CGImageRelease(imageRef);

    return cropped;
}
于 2015-01-06T06:52:25.523 に答える
23

Elmundoによるチェック済みの回答と、Imbrueによるその迅速なバージョンに基づいて、画像の中心のサイズを自動的に計算する同じソリューションを次に示します(向きを考慮に入れて)。エラーを考慮して、次のようにします。

func cropImageToSquare(image: UIImage) -> UIImage? {
    var imageHeight = image.size.height
    var imageWidth = image.size.width

    if imageHeight > imageWidth {
        imageHeight = imageWidth
    }
    else {
        imageWidth = imageHeight
    }

    let size = CGSize(width: imageWidth, height: imageHeight)

    let refWidth : CGFloat = CGFloat(CGImageGetWidth(image.CGImage))
    let refHeight : CGFloat = CGFloat(CGImageGetHeight(image.CGImage))

    let x = (refWidth - size.width) / 2
    let y = (refHeight - size.height) / 2

    let cropRect = CGRectMake(x, y, size.height, size.width)
    if let imageRef = CGImageCreateWithImageInRect(image.CGImage, cropRect) {
        return UIImage(CGImage: imageRef, scale: 0, orientation: image.imageOrientation)
    }

   return nil
}

Swift3バージョン

func cropImageToSquare(image: UIImage) -> UIImage? {
    var imageHeight = image.size.height
    var imageWidth = image.size.width

    if imageHeight > imageWidth {
        imageHeight = imageWidth
    }
    else {
        imageWidth = imageHeight
    }

    let size = CGSize(width: imageWidth, height: imageHeight)

    let refWidth : CGFloat = CGFloat(image.cgImage!.width)
    let refHeight : CGFloat = CGFloat(image.cgImage!.height)

    let x = (refWidth - size.width) / 2
    let y = (refHeight - size.height) / 2

    let cropRect = CGRect(x: x, y: y, width: size.height, height: size.width)
    if let imageRef = image.cgImage!.cropping(to: cropRect) {
        return UIImage(cgImage: imageRef, scale: 0, orientation: image.imageOrientation)
    }

    return nil
}
于 2015-11-23T12:25:53.100 に答える
13

次のようなものを試してください。

- (UIImage *)imageByCroppingImage:(UIImage *)image toSize:(CGSize)size
{
    double x = (image.size.width - size.width) / 2.0;
    double y = (image.size.height - size.height) / 2.0;

    CGRect cropRect = CGRectMake(x, y, size.height, size.width);
    CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);

    UIImage *cropped = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);

    return cropped;
}

ご覧のとおり、への呼び出しでは方向を指定していませんUIImage imageWithCGImage:。それがあなたのコードの問題なのだろうか。

于 2013-01-07T21:29:36.807 に答える
8

チェックされたソリューションの迅速なバージョンがあります:

private func imageByCroppingImage(image : UIImage, size : CGSize) -> UIImage{
        var refWidth : CGFloat = CGFloat(CGImageGetWidth(image.CGImage))
        var refHeight : CGFloat = CGFloat(CGImageGetHeight(image.CGImage))

        var x = (refWidth - size.width) / 2
        var y = (refHeight - size.height) / 2

        let cropRect = CGRectMake(x, y, size.height, size.width)
        let imageRef = CGImageCreateWithImageInRect(image.CGImage, cropRect)

        let cropped : UIImage = UIImage(CGImage: imageRef, scale: 0, orientation: image.imageOrientation)!


        return cropped
    }
于 2015-09-23T16:02:34.183 に答える
5

@Elmundoの回答から改善

+(UIImage *)getCenterMaxSquareImageByCroppingImage:(UIImage *)image withOrientation:(UIImageOrientation)imageOrientation

{
    CGSize centerSquareSize;
    double oriImgWid = CGImageGetWidth(image.CGImage);
    double oriImgHgt = CGImageGetHeight(image.CGImage);
    NSLog(@"oriImgWid==[%.1f], oriImgHgt==[%.1f]", oriImgWid, oriImgHgt);
    if(oriImgHgt <= oriImgWid) {
        centerSquareSize.width = oriImgHgt;
        centerSquareSize.height = oriImgHgt;
    }else {
        centerSquareSize.width = oriImgWid;
        centerSquareSize.height = oriImgWid;
    }

    NSLog(@"squareWid==[%.1f], squareHgt==[%.1f]", centerSquareSize.width, centerSquareSize.height);

    double x = (oriImgWid - centerSquareSize.width) / 2.0;
    double y = (oriImgHgt - centerSquareSize.height) / 2.0;
    NSLog(@"x==[%.1f], x==[%.1f]", x, y);

    CGRect cropRect = CGRectMake(x, y, centerSquareSize.height, centerSquareSize.width);
    CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);

    UIImage *cropped = [UIImage imageWithCGImage:imageRef scale:0.0 orientation:imageOrientation];
    CGImageRelease(imageRef);


    return cropped;
}
于 2015-04-15T07:02:21.040 に答える
5

これは、上記の@AlonzoのSwift 3の回答に基づいており、コードがより理解しやすく簡潔になるように簡略化および合理化されています。また、画像がすでに正方形である場合は、ベイルアウトします。

extension UIImage {
    func square() -> UIImage? {
        if size.width == size.height {
            return self
        }

        let cropWidth = min(size.width, size.height)

        let cropRect = CGRect(
            x: (size.width - cropWidth) * scale / 2.0,
            y: (size.height - cropWidth) * scale / 2.0,
            width: cropWidth * scale,
            height: cropWidth * scale
        )

        guard let imageRef = cgImage?.cropping(to: cropRect) else {
            return nil
        }

        return UIImage(cgImage: imageRef, scale: scale, orientation: imageOrientation)
    }
}
于 2017-06-08T14:20:58.790 に答える
4

これは古い質問ですが、実際に正しい答えはありません(受け入れられた答えでさえ)。理解しておくべき重要なことは、UIImageOrientationimage.imageOrientation)は実際には正しいということですが、UPの定義とUP定義は異なります。私たちにとって、UPはデバイスの上部(電源ボタンがある場所)です。の場合、UPは音量調節ボタンの反対側です。したがって、デバイスがボリュームコントロールを下げた状態で写真を撮る場合、これはです。ポートレートモード(ホームボタンを押したまま)で写真を撮る場合、これはです。UIImageOrientationUIImageOrientationUpUIImageOrientationLeft

したがって、縦向きの中心を計算してから、次の変換を画像に適用して、切り抜きが正しい場所に配置されるようにすることができます。

- (UIImage *)cropImage:(UIImage*)image toRect:(CGRect)rect {
    CGFloat (^rad)(CGFloat) = ^CGFloat(CGFloat deg) {
        return deg / 180.0f * (CGFloat) M_PI;
    };

    // determine the orientation of the image and apply a transformation to the crop rectangle to shift it to the correct position
    CGAffineTransform rectTransform;
    switch (image.imageOrientation) {
        case UIImageOrientationLeft:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -image.size.height);
            break;
        case UIImageOrientationRight:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -image.size.width, 0);
            break;
        case UIImageOrientationDown:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -image.size.width, -image.size.height);
            break;
        default:
            rectTransform = CGAffineTransformIdentity;
    };

    // adjust the transformation scale based on the image scale
    rectTransform = CGAffineTransformScale(rectTransform, image.scale, image.scale);

    // apply the transformation to the rect to create a new, shifted rect
    CGRect transformedCropSquare = CGRectApplyAffineTransform(rect, rectTransform);
    // use the rect to crop the image
    CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, transformedCropSquare);
    // create a new UIImage and set the scale and orientation appropriately
    UIImage *result = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
    // memory cleanup
    CGImageRelease(imageRef);

    return result;
}

このコードは、クロップスクエアをシフトして、正しい相対位置に配置します。

于 2015-06-15T18:07:44.360 に答える
4

UIImageExtensionを使用したSwift2

extension UIImage
{    
    func imageByCroppingImage(size : CGSize) -> UIImage
    {
        let refWidth : CGFloat = CGFloat(CGImageGetWidth(self.CGImage))
        let refHeight : CGFloat = CGFloat(CGImageGetHeight(self.CGImage))

        let x = (refWidth - size.width) / 2
        let y = (refHeight - size.height) / 2

        let cropRect = CGRectMake(x, y, size.width, size.height)
        let imageRef = CGImageCreateWithImageInRect(self.CGImage, cropRect)

        let cropped : UIImage = UIImage(CGImage: imageRef!, scale: 0, orientation: self.imageOrientation)


        return cropped
    }
}
于 2016-03-17T19:56:40.450 に答える
4

スウィフト3

    let refWidth : CGFloat = CGFloat(image.cgImage!.width)
    let refHeight : CGFloat = CGFloat(image.cgImage!.height)

    let x = (refWidth - size.width) / 2
    let y = (refHeight - size.height) / 2

    let cropRect = CGRect(x: x, y: y, width: size.width, height: size.height)
    let imageRef = image.cgImage!.cropping(to: cropRect)

    let cropped : UIImage = UIImage(cgImage: imageRef!, scale: 0, orientation: image.imageOrientation)


    return cropped
于 2016-09-15T15:34:43.897 に答える
1

UIImageViewから助けを得るのはどうですか

+ (UIImage *)laodSquareImage:(UIImage *)image withDiameter:(CGFloat)diameter  
{
    CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter);
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
    imageView.contentMode = UIViewContentModeScaleAspectFill;
    imageView.clipsToBounds = YES;
    imageView.image = image;
    CALayer *layer = imageView.layer;


    layer.masksToBounds = YES;
    UIGraphicsBeginImageContextWithOptions(imageView.bounds.size,NO, [UIScreen mainScreen].scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    [layer renderInContext:context];


    UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return roundedImage;
}

また、線を追加するだけでイメージサークルを作成することもできます。

layer.cornerRadius =MAX( imageView.frame.size.height,imageView.frame.size.width)/2;
于 2017-06-13T08:55:33.963 に答える
1

すでに多くの解決策がありますが、私は私のものを投稿したいと思います:

  extension UIImage {

    var cgImageWidth: Int { return cgImage?.width ?? 0 }
    var cgImageheight: Int { return cgImage?.height ?? 0 }
    var blance: CGFloat { return min(size.width, size.height)}
    var blanceSize: CGSize { return CGSize(width: blance, height: blance) }
    var blanceRect: CGRect { return CGRect(origin: .zero, size: blanceSize) }

    var roundedImage: UIImage? {
        UIGraphicsBeginImageContextWithOptions(blanceSize, false, scale)
        defer { UIGraphicsEndImageContext() }
        guard let cgImage = cgImage?.cropping(to: CGRect(origin: CGPoint(x: max(0, CGFloat(cgImageWidth) - blance)/2.0, y: max(0, CGFloat(cgImageheight) - blance)/2.0), size: blanceSize)) else { return nil }
        UIBezierPath(ovalIn: blanceRect).addClip()

        UIImage(cgImage: cgImage, scale: 1.0, orientation: self.imageOrientation).draw(in: blanceRect)
        return UIGraphicsGetImageFromCurrentImageContext()
    }

}
于 2017-07-20T06:53:58.440 に答える
1

Xamarin:

UIImage ImageByCroppingImage(UIImage image, CGSize size)
{
    double newCropWidth, newCropHeight;

    if (image.Size.Width < image.Size.Height)
    {
        newCropWidth = image.Size.Width < size.Width ? size.Width : image.Size.Width;
        newCropHeight = (newCropWidth * size.Height) / size.Width;
    }
    else
    {
        newCropHeight = image.Size.Height < size.Height ? size.Height : image.Size.Height;
        newCropWidth = (newCropHeight * size.Width) / size.Height;
    }

    double x = image.Size.Width / 2.0 - newCropWidth / 2.0;
    double y = image.Size.Height / 2.0 - newCropHeight / 2.0;

    CGRect cropRect = new CGRect(x, y, newCropWidth, newCropHeight);
    var imageRef = image.CGImage.WithImageInRect(cropRect);

    var cropped = new UIImage(imageRef);

    return cropped;
}
于 2018-02-27T04:23:13.657 に答える
1

Swift5の最もクリーンなバージョン。

func cropImage() -> UIImage? {
    let size = min(self.size.width, self.size.height)
    UIGraphicsBeginImageContextWithOptions(CGSize(width: size, height: size), true, 1.0)
    defer { UIGraphicsEndImageContext() }
    self.draw(in: CGRect(x: (size - self.size.width) / 2.0,
                          y: (size - self.size.height) / 2.0,
                          width: self.size.width,
                          height: self.size.height))
    return UIGraphicsGetImageFromCurrentImageContext()
}
于 2020-08-12T03:38:24.180 に答える
1

スウィフト5

extension UIImage {

    var squared: UIImage? {
        guard let cgImage = cgImage else {
            return nil
        }

        let length = min(cgImage.width, cgImage.height)

        let x = cgImage.width / 2 - length / 2
        let y = cgImage.height / 2 - length / 2
        let cropRect = CGRect(x: x, y: y, width: length, height: length)

        guard let croppedCGImage = cgImage.cropping(to: cropRect) else {
            return nil
        }

        return UIImage(cgImage: croppedCGImage, scale: scale, orientation: imageOrientation)
    }
}
于 2021-06-22T13:52:53.013 に答える
0

Swift2拡張に基づくソリューション。@Geoffreyと@NiravDangiから即興。newCropWidthとnewCropHeightは、指定された幅または高さよりも小さい場合は、画像の幅または高さに設定することに注意してください。

extension UIImage {
    func imageByCroppingImage(size: CGSize) -> UIImage {
        let newCropWidth, newCropHeight : CGFloat;

        if(self.size.width < self.size.height) {
            if (self.size.width < size.width) {
                newCropWidth = self.size.width;
            }
            else {
                newCropWidth = size.width;
            }
            newCropHeight = (newCropWidth * size.height)/size.width;
        } else {
            if (self.size.height < size.height) {
                newCropHeight = self.size.height;
            }
            else {
                newCropHeight = size.height;
            }
            newCropWidth = (newCropHeight * size.width)/size.height;
        }

        let x = self.size.width / 2 - newCropWidth / 2;
        let y = self.size.height / 2 - newCropHeight / 2;

        let cropRect = CGRectMake(x, y, newCropWidth, newCropHeight);
        let imageRef = CGImageCreateWithImageInRect(self.CGImage, cropRect);

        let croppedImage : UIImage = UIImage(CGImage: imageRef!, scale: 0, orientation: self.imageOrientation);

        return croppedImage;
    }
}
于 2016-05-12T04:56:43.593 に答える
0

私は以下を扱っています

    extension UIImage {

    var cgImageWidth: Int { return cgImage?.width ?? 0 }
    var cgImageheight: Int { return cgImage?.height ?? 0 }
    var blance: CGFloat { return min(size.width, size.height)}
    var blanceSize: CGSize { return CGSize(width: blance, height: blance) }
    var blanceRect: CGRect { return CGRect(origin: .zero, size: blanceSize) }

    var roundedImage: UIImage? {
        UIGraphicsBeginImageContextWithOptions(blanceSize, false, scale)
        defer { UIGraphicsEndImageContext() }
        guard let cgImage = cgImage?.cropping(to: CGRect(origin: CGPoint(x: max(0, CGFloat(cgImageWidth) - blance)/2.0, y: max(0, CGFloat(cgImageheight) - blance)/2.0), size: blanceSize)) else { return nil }
        UIBezierPath(ovalIn: blanceRect).addClip()

        UIImage(cgImage: cgImage, scale: 1.0, orientation: self.imageOrientation).draw(in: blanceRect)
        return UIGraphicsGetImageFromCurrentImageContext()
    }

}
于 2017-07-20T07:07:33.687 に答える
0

これは、中央から指定されたサイズに従って画像をトリミングするSwift5バージョンです。

extension UIImage {

     func imageByCroppingImage(size : CGSize) -> UIImage{
        let refWidth : CGFloat = CGFloat(self.cgImage!.width)
        let refHeight : CGFloat = CGFloat(self.cgImage!.height)
        let x = (refWidth - size.width) / 2
        let y = (refHeight - size.height) / 2
        let cropRect = CGRect(x: x, y: y, width: size.width, height: size.height)
        let imageRef = self.cgImage!.cropping(to: cropRect)
        let cropped : UIImage = UIImage(cgImage: imageRef!, scale: 0, orientation: self.imageOrientation)
        return cropped
    }
    }
于 2020-04-10T22:44:32.940 に答える
-3

私はこのようなものでそれを達成することができました:

   UIImage *thisImage = [[UIImage alloc] initWithContentsOfFile:imagePath];
                double x = (thisImage.size.width )/2.0;
                double y = (thisImage.size.height)/2.0;
                mediaImage = [self imageByCropping:thisImage toRect:CGRectMake(x, y, 60, 60)];
                [thisImage release];
于 2013-02-25T17:36:33.300 に答える