Маска не работает при захвате uiview для uiimage

У меня есть UIView, который я хочу сохранить как UIImage. Я делаю это с помощью UIGraphicsBeginImageContext, и он работает нормально. Но когда я применяю маску к изображениям в (view/layer.mask), изображение, которое я захватываю через UIGraphicsBeginImageContext, ошибочно (маскирование работает при запуске приложения, но не при попытке получить UIImage из UIView). Кто-нибудь сталкивался с подобной проблемой?

Ответ 1

Если я правильно понимаю, вы хотите создать UIImage из слоя UIView, в то время как этот слой замаскирован. Я предполагаю, что вы хотите, чтобы целевой UIImage имел прозрачный фон.

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

https://bitbucket.org/reydan/so_imagemask

Сначала вам нужно нажать кнопку Маска. Он загрузит изображение маски (черно-белое) из пакета и установит его как маску слоя для контейнера UIView выше.

Затем вы можете нажать кнопку Копировать изображение, которая отображает контейнер UIView в UIImage, а затем установите его в изображение целевого изображения ниже, чтобы увидеть результат.

Я также опубликую здесь 2 метода:

- (IBAction)onMask:(id)sender {

    UIImage* maskImage = [UIImage imageNamed:@"star.png"];
    UIImageView* maskImageView = [[UIImageView alloc] initWithImage:maskImage];
    maskImageView.contentMode = UIViewContentModeScaleAspectFit;
    maskImageView.frame = _mainContainerView.bounds;

    _mainContainerView.layer.mask = maskImageView.layer;
}

- (IBAction)onCopyImage:(id)sender {

    UIGraphicsBeginImageContextWithOptions(_mainContainerView.bounds.size, FALSE, [[UIScreen mainScreen] scale]);
    [_mainContainerView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    _destImageView.image = img;
}

ИЗМЕНИТЬ

По-видимому, renderInContext: на IOS6 не использует маску (как сказано здесь и на SO). Мое решение состояло в том, чтобы вручную применить маску к изображению. Маска берется из свойства маски слоя и визуализируется в контексте, поэтому у нас нет проблем с преобразованиями /contentModes/etc.

Вот обновленный исходный код (он также доступен на битбакете):

- (IBAction)onCopyImage:(id)sender {

    // Get the image from the mainImageView
    UIGraphicsBeginImageContextWithOptions(_mainContainerView.bounds.size, FALSE, [[UIScreen mainScreen] scale]);
    [_mainContainerView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();


    // Use the next block if targeting IOS6
    {
        // Manually create a mask image (taken from the mask layer)
        UIGraphicsBeginImageContextWithOptions(_mainContainerView.bounds.size, TRUE, [[UIScreen mainScreen] scale]);

        CGContextRef ctx = UIGraphicsGetCurrentContext();
        CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor);
        CGContextFillRect(ctx, _mainContainerView.bounds);

        [_mainContainerView.layer.mask renderInContext:ctx];
        UIImage * maskimg = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();


        // Create a image mask from the UIImage
        CGImageRef maskRef = maskimg.CGImage;
        CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                            CGImageGetHeight(maskRef),
                                            CGImageGetBitsPerComponent(maskRef),
                                            CGImageGetBitsPerPixel(maskRef),
                                            CGImageGetBytesPerRow(maskRef),
                                            CGImageGetDataProvider(maskRef), NULL, false);

        // Apply the mask to our source image
        CGImageRef maskedimg= CGImageCreateWithMask(img.CGImage, mask);

        // Convert to UIImage so we can easily display it in a UIImageView
        img = [UIImage imageWithCGImage:maskedimg scale:img.scale orientation:img.imageOrientation];

        CGImageRelease(mask);
        CGImageRelease(maskedimg);
    }



    _destImageView.image = img;

}

ИЗМЕНИТЬ Пожалуйста, проверьте последний проект на битбакете, поскольку он содержит последнюю версию.

Ответ 2

Вот пример кода, который я использовал для получения UIView как изображения UIImageView и Apply mask для этого.

 * UIView --> UIImageView --> With Mask images .

Я использовал UIView для рисования для этого,

Назначение UIView (рисованной области) в UIImageView.

-(UIImage*) imageRepresentation
{
    [EAGLContext setCurrentContext:context];
    UIImageView* upsideDownImageView=[[UIImageView alloc] initWithImage: [self upsideDownImageRepresenation]];

    upsideDownImageView.transform=CGAffineTransformScale(upsideDownImageView.transform, 1, -1);

    UIView* container=[[UIView alloc] initWithFrame:upsideDownImageView.frame];
    [container addSubview:upsideDownImageView];
    UIImage* toReturn=nil;

    UIGraphicsBeginImageContext(container.frame.size);

    [container.layer renderInContext:UIGraphicsGetCurrentContext()];

    toReturn = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    //[upsideDownImageView release];
    upsideDownImageView = nil;
    container = nil;
    //[container release];
    return toReturn;
}


-(UIImage*) upsideDownImageRepresenation
{
    int imageWidth = CGRectGetWidth([self bounds]);
    int imageHeight = CGRectGetHeight([self bounds]);

    //image buffer for export
    NSInteger myDataLength = imageWidth* imageHeight * 4;

    // allocate array and read pixels into it.
    GLubyte *tempImagebuffer = (GLubyte *) malloc(myDataLength);

    glReadPixels( 0, 0, imageWidth, imageHeight, GL_RGBA, GL_UNSIGNED_BYTE, tempImagebuffer);

    // make data provider with data.
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, tempImagebuffer, myDataLength, ProviderReleaseData);

    // prep the ingredients
    int bitsPerComponent = 8;

   int bitsPerPixel = 32;
    int bytesPerRow = 4 * imageWidth;
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast;

    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

    // make the cgimage
    CGImageRef imageRef = CGImageCreate(imageWidth, imageHeight, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);

    // then make the uiimage from that
    UIImage *myImage =  [UIImage imageWithCGImage:imageRef] ;

    CGDataProviderRelease(provider);
    CGImageRelease(imageRef);
    CGColorSpaceRelease(colorSpaceRef);

    return myImage;
}

Теперь у вас есть представление UIImageView UIView.

Теперь давайте сделаем это с эффектом маски.

 UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0); //imageView is wt we got by converting the UIIVew.
        [self.imageView.layer renderInContext:UIGraphicsGetCurrentContext()];
// Add the mask Images even if want any UILabels etc ..
        [imageView.image drawInRect:CGRectMake(0, 0, 703, 315)];
        [maskImages.image drawAtPoint:CGPointMake(10, 10) blendMode:kCGBlendModeNormal alpha:0.2];
        [lblAckNo drawTextInRect:CGRectMake(320, 230,100,50)];

        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();// image with all of your effort.
        [[UIColor redColor] set];

         UIGraphicsEndImageContext();