Могу ли я отредактировать альфа-маску пользовательского изображения в UIImageView без необходимости перемещать слишком много памяти?

#iphone #ios #uiimage #quartz-graphics #cgimage

#iPhone #iOS #uiimage #quartz-graphics #cgimage

Вопрос:

Я хочу взять изображение (кисть) и нарисовать его в отображаемом изображении. Я хочу повлиять только на альфа-версию этого изображения, и мне нужно экспортировать его позже.

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

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

Что я хотел бы сделать, это взять UIImage UIImageView и напрямую управлять его альфа-каналом. Я также делаю это не попиксельно, а с помощью большой (радиус 20 пикселей) кисти, которая сама по себе мягче.

Ответ №1:

Я бы не стал использовать UIImageView для этого. Достаточно обычного UIView.

Просто поместите изображение в слой с

 UIView *view = ...
view.layer.contents = (id)image.CGImage;
  

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

 CALayer *mask = [[CALayer alloc] init]
mask.contents = maskimage.CGImage;
view.layer.mask = mask;
  

для проекта я сделал кое-что, где у меня была кисть в формате png, которую можно использовать для отображения изображения пальцем… моя функция обновления маски там была:

 - (void)updateMask {

    const CGSize size = self.bounds.size;
    const size_t bitsPerComponent = 8;
    const size_t bytesPerRow = size.width; //1byte per pixel
    BOOL freshData = NO;
    if(NULL == _maskData || !CGSizeEqualToSize(size, _maskSize)) {
        _maskData = calloc(sizeof(char), bytesPerRow * size.height);
        _maskSize = size;
        freshData = YES;
    }

    //release the ref to the bitmat context so it doesn't get copied when we manipulate it later
    _maskLayer.contents = nil;
    //create a context to draw into the mask
    CGContextRef context = 
    CGBitmapContextCreate(_maskData, size.width, size.height, 
                          bitsPerComponent, bytesPerRow,
                          NULL,
                          kCGImageAlphaOnly);
    if(NULL == context) {
        LogDebug(@"Could not create the context");
        return;
    }

    if(freshData) {
        //fill with mask with alpha == 0, which means nothing gets revealed
        CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
        CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));    
    }

    CGContextTranslateCTM(context, 0, self.bounds.size.height);
    CGContextScaleCTM(context, 1.0f, -1.0f);

    //Draw all the points in the array into a mask
    for (NSValue* pointValue in _pointsToDraw)
    {
        CGPoint point;
        [pointValue getValue:amp;point];
        //LogDebug(@"location: %@", NSStringFromCGPoint(point));

        [self drawBrush:[_brush CGImage] at:point inContext:context];
    }
    [_pointsToDraw removeAllObjects];

    //extract an image from it
    CGImageRef newMask = CGBitmapContextCreateImage(context);

    //release the context
    CGContextRelease(context);

    //now update the mask layer
    _maskLayer.contents = (id)newMask;
    //self.layer.contents = (id)newMask;
    //and release the mask as it's retained by the layer
    CGImageRelease(newMask);
}
  

Комментарии:

1. Итак, мне нужно изменить только базовое maskImage? Является ли лучший способ сделать это по-прежнему просто постоянным восстановлением CGImage из отредактированного контекста? Я также полагаю, что это сведет на нет мои усилия заставить ее работать внутри scrollview? Потому что я ранее использовал это для центрирования и масштабирования.

2. Это работает, за исключением того, что мне нужно ввести альфа-версию маски. Но когда у вас есть CGImage с 0 alpha, он не вписывается в контекст, потому что это 0 alpha! Какой режим рисования позволит вам записывать в маску?

3. Я думаю, проблема в том, что вы не можете изменить cgimage … Я настраиваю контекст растрового изображения, который кэширую, изменяю и копирую его в маску при каждом обновлении маски, используя CGBitmapContextCreateImage

4. Это работает, за исключением ранее упомянутых проблем с альфа-интерфейсом. Производительность хороша при простом изменении изображения маски. Не уверен, но, возможно, придется изменить режим.

5. Я бы поставил 1, если бы вы прикрепили пример кода или добавили другие функции.