Преобразование CGContext, чтобы извлечь повернутый прямоугольник
Мое намерение состоит в том, чтобы написать функцию, которая может извлечь повернутую прямоугольную часть большего изображения. Эта повернутая прямоугольная часть описывается с центральной точкой (от 0,0 до полной ширины / высоты изображения), размером и углом поворота.
Я волнуюсь, что я не понимаю что-то о CGContexts. Я знаю, что после вращения мое координатное пространство вращается.
Эта функция всегда работает, если угол равен 0, и кажется правильной, если угол небольшой. Однако с увеличением угла все смещается неправильно.
Я вычисляю верхний левый угол с помощью аффинного преобразования, аналогичного преобразованию изображения, чтобы избежать любой неточности. Я также попытался изменить верхний левый угол, применив к нему преобразование изображения, а также обратное преобразование изображения (как случайную мысль).
Будет ли этот подход работать? Я где-то пропускаю космическое преобразование?
Примечание. Было очень легко заштриховать область изображения, нарисовав полное изображение, а затем нарисовав черный прямоугольник в правильном положении с правильным размером и вращением. Учитывая это, я знаю, что мои данные верны.
Зрительные:
Это представляет полное изображение, и повернутый прямоугольник, который я пытаюсь попробовать:
Это изображение представляет желаемый результат этой функции:
- (UIImage*) croppedImage:(UIImage*) image center:(CGPoint) rotationCenter size:(CGSize) size rotation:(CGFloat) rotation
{
CGFloat fullWidth = image.size.width;
CGFloat fullHeight = image.size.height;
CGRect imageRect = CGRectMake(0, 0, fullWidth, fullHeight);
//must convert UI space to CG space, in this case that just means adjusting the y coordinate
rotationCenter.y = fullHeight - rotationCenter.y;
CGFloat width = size.width;
CGFloat height = size.height;
int flags = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast;
CGContextRef btx = CGBitmapContextCreate(NULL, width, height, 8, 0, CGColorSpaceCreateDeviceRGB(), flags);
CGContextSetAllowsAntialiasing(btx, YES);
CGContextSetShouldAntialias(btx, YES);
//use a transformation to rotate at the center of the request area
CGAffineTransform imageTransform = CGAffineTransformIdentity;
imageTransform = CGAffineTransformTranslate(imageTransform, rotationCenter.x, rotationCenter.y);
imageTransform = CGAffineTransformRotate(imageTransform, rotation);
imageTransform = CGAffineTransformTranslate(imageTransform, -rotationCenter.x, -rotationCenter.y);
//use a transformation to determine the top-left coordinate of the rect
CGAffineTransform ptTransform = CGAffineTransformIdentity;
ptTransform = CGAffineTransformTranslate(ptTransform, rotationCenter.x, rotationCenter.y);
ptTransform = CGAffineTransformRotate(ptTransform, rotation);
ptTransform = CGAffineTransformTranslate(ptTransform, -width/2.0, -height/2.0);
//this gets me the position of the top-left corner of the image no matter the rotation
CGPoint topleft = CGPointApplyAffineTransform(CGPointZero, ptTransform);
CGContextConcatCTM(btx, imageTransform);
//move the image away from the origin, to align origin with where i want my image sampled from
CGContextTranslateCTM(btx, -topleft.x,
-topleft.y);
//Close... but wrong
CGContextDrawImage(btx, imageRect, image.CGImage);
CGImageRef img = CGBitmapContextCreateImage(btx);
UIImage* uiimage = [UIImage imageWithCGImage:img scale:image.scale orientation:image.imageOrientation];
CGContextRelease(btx);
CGImageRelease(img);
return uiimage;
}
1 ответ
Я полагаю, что вы описываете такие вещи:
Это действительно запущенное приложение для iOS, так что вы можете увидеть, что я сделал: на первом рисунке я нарисовал синим прямоугольник, который я хочу захватить, и показал результат в виде изображения; на втором снимке я его запечатлел и показал, что результат в виде изображения.
Как вы можете видеть, внимательно посмотрев по краям второго изображения, мы точно зафиксировали содержимое синего прямоугольника.
Итак, теперь я полагаю, вы хотите знать, как я это сделал? Синий прямоугольник был нарисован с использованием трех частей информации: верхний левый угол прямоугольника topLeft
, размер прямоугольника size
и вращение rot
, Чтобы упростить вещи, я проигнорировал ваш разговор о "центре"; Я повернулся вокруг верхнего левого.
Затем второе изображение было получено путем создания графического контекста размера size
вращая это негатив rot
и рисование полного исходного изображения в негативе topLeft
, Фактическая часть рисования - это всего две строки кода (извините, я пишу и думаю в Свифт в наши дни, но я уверен, что вы можете перевести):
CGContextRotateCTM(context, -rot)
im.drawAtPoint(CGPointMake(-topLeft.x, -topLeft.y))
Поэтому я думаю, что мой ответ в конечном итоге таков: это очень просто и работает так, как вы ожидаете, если вы превратите свое первоначальное описание в то, что вы хотите сделать, чтобы topLeft
вместо центра.