iOS: создание обтравочного контура изображения из UIBezierPath - PullRequest
3 голосов
/ 28 июля 2011

Я создаю приложение, которое позволяет пользователям вырезать часть изображения.Для этого они создадут группу UIBezierPath для формирования обтравочного контура.Моя текущая настройка выглядит следующим образом:

  • UIImageView отображает изображение, которое они режут.
  • Выше этого UIImageView является пользовательским подклассом UIImageView, который выполняет пользовательские методы drawRect: для отображения/ Обновление UIBezierPath, которые добавляет пользователь.
  • Когда пользователь нажимает кнопку «Готово», создается новый объект UIBezierPath, который включает в себя все отдельные пути, созданные пользователем, путем циклического перемещения по массиву, в котором они находятся.хранится в и вызывает appendPath: на себя.Этот новый UIBezierPath затем закрывает свой путь.

Это все, что я получил.Я знаю, что в UIBezierPath есть метод addClip, но я не могу понять из документации, как его использовать.

В общем, все примеры, которые я видел для отсечения, напрямую используют Core Graphics, а не оболочку UIBezierPath.Я понимаю, что UIBezierPath имеет свойство CGPath.Так должен ли я использовать это во время отсечения, а не полный объект UIBezierPath?

1 Ответ

0 голосов
/ 09 апреля 2012

Apple говорит, что не следует создавать подкласс UIImageView, в соответствии с ссылкой на класс UIImageView .Спасибо @rob mayoff за указание на это.

Однако, если вы реализуете свой собственный drawRect, начните с собственного подкласса UIView.И внутри drawRect вы используете addClip.Вы можете сделать это с помощью UIBezierPath, не преобразовывая его в CGPath.

- (void)drawRect:(CGRect)rect
{
    // This assumes the clippingPath and image may be drawn in the current coordinate space.
    [[self clippingPath] addClip];
    [[self image] drawAtPoint:CGPointZero];
}

Если вы хотите увеличить или уменьшить масштаб, чтобы заполнить границы, вам нужно масштабировать графический контекст.(Вы также можете применить CGAffineTransform к clippingPath, но это является постоянным, поэтому вам сначала нужно скопировать clippingPath.)

- (void)drawRect:(CGRect)rect
{
    // This assumes the clippingPath and image are in the same coordinate space, and scales both to fill the view bounds.
    if ([self image])
    {
        CGSize imageSize = [[self image] size];
        CGRect bounds = [self bounds];

        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextScaleCTM(context, bounds.size.width/imageSize.width, bounds.size.height/imageSize.height);

        [[self clippingPath] addClip];
        [[self image] drawAtPoint:CGPointZero];
    }
}

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

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

- (void) setImage:(UIImage *)image;
{
    // This method should also store the image for later retrieval.
    // Putting an image directly into a CALayer will stretch the image to fill the layer.
    [[self layer] setContents:(id) [image CGImage]];
}

- (void) setClippingPath:(UIBezierPath *)clippingPath;
{
    // This method should also store the clippingPath for later retrieval.
    if (![[self layer] mask])
        [[self layer] setMask:[CAShapeLayer layer]];

    [(CAShapeLayer*) [[self layer] mask] setPath:[clippingPath CGPath]];
}

Если вы делаете обрезку изображения с помощью масок слоев, вам больше не нужен метод drawRect.Снимите его для эффективности.

...