поворот изображения с помощью CGContextDrawImage

как я могу повернуть изображение запряженной CGContextDrawImage() в центре?

на drawRect:

                CGContextSaveGState(c);


                rect = CGRectOffset(rect, -rect.size.width / 2, -rect.size.height / 2);
                CGContextRotateCTM(c, angle);
                CGContextDrawImage(c, rect, doodad.CGImage);
                CGContextRotateCTM(c, -angle);
                CGContextTranslateCTM(c, pt.x, pt.y);

                prevRect = rect;

                CGContextRestoreGState(c);

Я рисую изображение в начале координат и поворачиваю его в центре, а затем переводю туда, где оно должно быть нарисовано. Не работать.

4 ответов


что нужно помнить о преобразованиях координат-ну один из вещей, которые нужно помнить-это то, что вы не манипулируете объектами, как команда Transform в графическом редакторе; вы манипулируете пробел.

представьте, что устройство подвешено над столом на руке с гусиной шеей и зафиксировано в положении. Преобразования координат перемещают стол (перевод) и поворачивают его так или иначе (вращение) и даже сквош и растянуть его (масштабирование).

еще одна вещь, которую нужно помнить о преобразованиях координат, - это то, что преобразование всегда относительно начала координат. Представьте, что ваш стол начинается с одного из его углов-соответствующего углу вашего вида-прямо под углом, где ваш вид заканчивается на экране. Перевод перемещает угол стола и остальную часть стола вместе с ним, перемещая его так или иначе под экран. Вращать поворачивает стол вокруг тот угол.

еще одна вещь: преобразования влияют на будущее, а не на прошлое. Нарисовать что-то, а затем попытаться преобразовать это не сработает, потому что вы не преобразуете то, что нарисовали, вы трансформируете пространство, в которое собираетесь нарисовать. Итак, нам нужно передвинуть стол, прежде чем мы сможем поместить изображение в нужное место.

(я упоминаю эту последнюю часть, потому что у вас есть пара команд преобразования, которые немедленно возвращаются вашим CGContextRestoreGState звонок. Нет рисование для них влиять.)

Итак, давайте начнем с невращающегося прямоугольника изображения.

CGRect imageRect = { pointWhereYouWantTheImageCentered, doodad.size };

теперь CGContextDrawImage принимает прямоугольник, но, как вы знаете, он будет рисовать изображение из нижнего левого угла этого прямоугольника, а не из центра. (Отсюда и все это упражнение.)

Итак, вот что вы собираетесь делать. В конце этого, вы собираетесь нарисовать не в этой точке, показанной выше, но в нулевой точке-это, на самом углу стола. (Не в центре угла, а с углом изображения на углу стола.)

как это будет работать? Это требует некоторой настройки. Тебе придется передвинуть свой стол.

во-первых, вам нужно переместить свой стол до и право пока исходный угол вашего стола не окажется в нужной центральной точке:

CGContextTranslateCTM(context, imageRect.origin.x, imageRect.origin.y);

затем вы делаете вращение (поворачивая стол вокруг его начала угол):

CGContextRotateCTM(context, angleInRadians);

затем переместите стол вниз и левый на половину ширины и высоты изображения:

CGContextTranslateCTM(context, imageRect.size.width * -0.5, imageRect.size.height * -0.5);

и, наконец, поместите изображение на угол стола.

CGContextDrawImage(context, (CGRect){ CGPointZero, imageRect.size }, [doodad CGImage]);

когда ваш стол так перемещен, центр этого прямоугольника лежит прямо под точкой на экране, где вы хотите, чтобы изображение было центрировано, поэтому изображение настолько центрировано.


эта функция может рисовать изображение на существующем изображении с углом поворота в радианах.

Swift 3:

extension UIImage {
    func putImage(image: UIImage, on rect: CGRect, angle: CGFloat = 0.0) -> UIImage{

        let drawRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        UIGraphicsBeginImageContextWithOptions(drawRect.size, false, 1.0)

        // Start drawing self
        self.draw(in: drawRect)

        // Drawing new image on top
        let context = UIGraphicsGetCurrentContext()!

        // Get the center of new image
        let center = CGPoint(x: rect.midX, y: rect.midY)

        // Set center of image as context action point, so rotation works right
        context.translateBy(x: center.x, y: center.y)
        context.saveGState()

        // Rotate the context
        context.rotate(by: angle)

        // Context origin is image's center. So should draw image on point on origin
        image.draw(in: CGRect(origin: CGPoint(x: -rect.size.width/2, y: -rect.size.height/2), size: rect.size), blendMode: .normal, alpha:
1.0)

        // Go back to context original state.
        context.restoreGState()

        // Get new image
        let newImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()

        return newImage
    }

}

Если вам нужно создать и пустое изображение с размером и цветом, использовать:

extension UIImage {
    convenience init?(size: CGSize, color: UIColor) {
        let rect = CGRect(origin: .zero, size: size)
        UIGraphicsBeginImageContextWithOptions(rect.size, true, 1.0)
        color.setFill()
        UIRectFill(rect)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        guard let cgImage = image?.cgImage else { return nil }
        self.init(cgImage: cgImage)
    }
}

Вы можете использовать следующий метод для вращения изображения.

-(UIImage*)rotateImage:(UIImage*)img forAngle:(CGFloat)radian   {

    UIView *rotatedViewBox = [[UIView alloc]initWithFrame:CGRectMake(0, 0, img.size.width, img.size.height)];
    CGAffineTransform t = CGAffineTransformMakeRotation(radian);
    rotatedViewBox.transform = t;
    CGSize rotatedSize = rotatedViewBox.frame.size;

    UIGraphicsBeginImageContext(rotatedSize);

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context, rotatedSize.width, rotatedSize.height);
    CGContextRotateCTM(context, radian);
    CGContextScaleCTM(context, 1.0, -1.0);

    CGContextDrawImage(context, CGRectMake(-img.size.width, -img.size.height, img.size.width, img.size.height), img.CGImage);
    UIImage *returnImg = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();
    return returnImg;
}

Если вы используете угол, то вот макрос для преобразования градусов в радиане

#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)

Если вы в конечном итоге рисуете на экран (в отличие от создания изображения для сохранения в файл), вы можете вообще не использовать CGContext, а скорее поместить изображение в CALayer и повернуть слой вокруг его точки привязки:

[layer setValue:@(rotationInRadians) forKeyPath:@"transform.rotation.z"];

Если изображение само генерируется (в отличие от статического ресурса из вашего пакета или чего-то пользовательского), вы можете рассмотреть возможность создания его из слоев и установки sublayerTransform их родителя / общего предка слой:

[layerContainingTheConstituentLayers setValue:@(rotationInRadians) forKeyPath:@"sublayerTransform.rotation.z"];

(могут быть способы сделать это с представлениями вместо слоев; я парень Mac, поэтому я не знаю UIView очень глубоко.)