Как часть моего редактора 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 находится здесь .