Как часть моего редактора Swift Image Tone Curve , я хотел нарисовать плавный сплайн, проходящий через несколько точек. В Swift нет ничего «стандартного», чтобы сделать это — стандартный UIBezierPath может рисовать кубические и квадратичные кривые Безье, но требуется немного усилий, чтобы установить контрольные точки, чтобы сделать хорошую непрерывную кривую.
Есть два общих решения: Catmull Rom и Hermite . К счастью, я обнаружил, что эта замечательная статья обсуждает реализацию как в Objective-C, так и в более удачной форме, включая исходный код . Поэтому мне не понадобилось много времени, чтобы перенести этот код в Swift и реализовать его как расширение UIBezierPath .
Чтобы использовать мое расширение, просто создайте экземпляр UIBezierPath , создайте массив экземпляров CGPoint — точек, через которые вы хотите, чтобы ваша кривая прошла, — и вызовите interpolatePointsWithHermite () с массивом. Итак, теперь переопределенный метод drawInContext () в классе ToneCurveEditorCurveLayer моего редактора тоновых кривых выглядит следующим образом:
override func drawInContext(ctx: CGContext!)
{
if let curveValues = toneCurveEditor?.curveValues
{
var path = UIBezierPath()
let margin = 20
let thumbRadius = 15
let widgetWidth = Int(frame.width)
let widgetHeight = Int(frame.height) - margin - margin - thumbRadius - thumbRadius
var interpolationPoints : [CGPoint] = [CGPoint]()
for (i: Int, value: Double) in enumerate(curveValues)
{
let pathPointX = i * (widgetWidth / curveValues.count) + (widgetWidth / curveValues.count / 2)
let pathPointY = thumbRadius + margin + widgetHeight - Int(Double(widgetHeight) * value)
interpolationPoints.append(CGPoint(x: pathPointX,y: pathPointY))
}
path.interpolatePointsWithHermite(interpolationPoints)
CGContextSetLineJoin(ctx, kCGLineJoinRound)
CGContextAddPath(ctx, path.CGPath)
CGContextSetStrokeColorWithColor(ctx, UIColor.blueColor().CGColor)
CGContextSetLineWidth(ctx, 6)
CGContextStrokePath(ctx)
}
}
Мое второе полезное расширение (и то, которое я написал сам на этот раз!) Находится на UIImage и изменяет размеры изображений. Мне нужно было сделать это, потому что применение фильтров к огромным изображениям может быть мучительно медленным и пожирать память. При редактировании не требуется применять фильтры к полноразмерному изображению, поэтому изменение размера позволяет моему небольшому приложению использовать прокси.
Это расширение принимает один аргумент, который является стороной ограничивающего квадрата. Возвращенное изображение правильно масштабируется, чтобы поместиться в этом поле
extension UIImage
{
func resizeToBoundingSquare(#boundingSquareSideLength : CGFloat) -> UIImage
{
let imgScale = self.size.width > self.size.height ? boundingSquareSideLength / self.size.width : boundingSquareSideLength / self.size.height
let newWidth = self.size.width * imgScale
let newHeight = self.size.height * imgScale
let newSize = CGSize(width: newWidth, height: newHeight)
UIGraphicsBeginImageContext(newSize)
self.drawInRect(CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
return resizedImage
}
}
… функция возвращает новое изображение и может быть вызвана так:
loadedImage = rawImage.resizeToBoundingSquare (boundingSquareSideLength: 1024)
Это заполняет загруженный образ копией rawImage с максимальным размером 1024 пикселей.
Оба расширения доступны в моем репозитории GitHub. Расширение UIBezierPath является здесь и расширение UIImage находится здесь .
