Подтвердить что ты не робот

Любая идея, почему этот код маскировки изображений не работает?

У меня есть этот код для маскировки изображения. В основном, я работаю только с изображениями PNG. Итак, у меня есть PNG-изображение 300x400 с 24-битным цветом (PNG-24). Я не уверен, что у него также есть альфа-канал. Но в этом нет прозрачности.

Тогда есть маска изображения, которая является PNG-8 бит без альфа-канала. Это только черный, полутоновый и белый.

Я создаю оба изображения как UIImage. Оба дисплея отображаются правильно, когда помещаются в UIImageView.

Затем я создаю из них UIImage, который содержит результаты операции маскировки, с помощью этого кода:

+ (UIImage*)maskImage:(UIImage*)image withMask:(UIImage*)maskImage {
 CGImageRef maskRef = maskImage.CGImage;
 CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
          CGImageGetHeight(maskRef),
          CGImageGetBitsPerComponent(maskRef),
          CGImageGetBitsPerPixel(maskRef),
          CGImageGetBytesPerRow(maskRef),
          CGImageGetDataProvider(maskRef), NULL, false);
 CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
 return [UIImage imageWithCGImage:masked];
}

вот что я делаю с этим:

 UIImage *image = [UIImage imageNamed:@"coloredImagePNG24.png"];
 UIImage *maskImage = [UIImage imageNamed:@"theMaskPNG8_Grayscale_NoAlpha.png"];
 UIImage *maskedImage = [MyGraphicUtils maskImage:image withMask:maskImage];
 UIImageView *testImageView = [[UIImageView alloc] initWithImage:maskedImage];
 testImageView.backgroundColor = [UIColor clearColor];
 testImageView.opaque = NO;

В конце концов, colorImagePNG24.png остается полностью неповрежденным. Никакой маскировки не происходит. Но теперь это странно: если я поверну это, то используйте это изображение как маску, а маску, как цветное изображение в маску, тогда я получаю что-то очень уродливое в оттенках серого (но в масках;)).

Любая идея, что не так с моим кодом?

UPDATE: я просто искал Google для другого b/w png, чтобы использовать его в качестве маски. А потом это сработало! Но тот, который я сделал сам, не работает. Поэтому я предполагаю, что код имеет большие проблемы декодирования изображений. Я должен "нормализовать" изображения в определенном формате, чтобы он работал.

4b9b3361

Ответ 1

Этот код может помочь вам

- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {

    CGImageRef maskRef = maskImage.CGImage; 

    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
        CGImageGetHeight(maskRef),
        CGImageGetBitsPerComponent(maskRef),
        CGImageGetBitsPerPixel(maskRef),
        CGImageGetBytesPerRow(maskRef),
        CGImageGetDataProvider(maskRef), NULL, false);

    CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
    return [UIImage imageWithCGImage:masked];

}

см. эту демонстрацию

Ответ 2

Как вы выяснили, как сохранить файл может иметь значение, потому что Core Graphics очень специфична в отношении формата бит, который он использует для маскировки.

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

  • Создайте графический контекст растровой графики, который находится в приемлемом формате для масок изображений (для этого вы не можете использовать UIGraphicsBeginImageContext())
  • Нарисуйте изображение в этом графическом контексте с растровой графикой.
  • Создайте маску изображения из бит графического контекста графической подписи.

Попробуйте эту функцию:

CGImageRef createMaskWithImage(CGImageRef image)
{
    int maskWidth               = CGImageGetWidth(image);
    int maskHeight              = CGImageGetHeight(image);
    //  round bytesPerRow to the nearest 16 bytes, for performance sake
    int bytesPerRow             = (maskWidth + 15) & 0xfffffff0;
    int bufferSize              = bytesPerRow * maskHeight;

    //  allocate memory for the bits 
    CFMutableDataRef dataBuffer = CFDataCreateMutable(kCFAllocatorDefault, 0);
    CFDataSetLength(dataBuffer, bufferSize);

    //  the data will be 8 bits per pixel, no alpha
    CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceGray();
    CGContextRef ctx            = CGBitmapContextCreate(CFDataGetMutableBytePtr(dataBuffer),
                                                        maskWidth, maskHeight,
                                                        8, bytesPerRow, colourSpace, kCGImageAlphaNone);
    //  drawing into this context will draw into the dataBuffer.
    CGContextDrawImage(ctx, CGRectMake(0, 0, maskWidth, maskHeight), image);
    CGContextRelease(ctx);

    //  now make a mask from the data.
    CGDataProviderRef dataProvider  = CGDataProviderCreateWithCFData(dataBuffer);
    CGImageRef mask                 = CGImageMaskCreate(maskWidth, maskHeight, 8, 8, bytesPerRow,
                                                        dataProvider, NULL, FALSE);

    CGDataProviderRelease(dataProvider);
    CGColorSpaceRelease(colourSpace);
    CFRelease(dataBuffer);

    return mask;
}

Ответ 3

CGImageMaskCreate не выполняет то, что вы ожидаете. В частности:

Для масок изображений, которые являются 2, 4 или 8 бит на компонент, каждый компонент отображается в диапазоне от 0 до 1 путем масштабирования с использованием этой формулы:

1/(2 ^ бит на компонент - 1)

Например, 4-разрядная маска имеет значения от 0 до 15. Эти значения масштабируются на 1/15, так что каждый компонент находится в диапазоне от 0 до 1. Значения компонентов, которые изменяются до 0 или 1, ведут себя одинаково поскольку они ведут себя для 1-битных масок изображения. Значения, которые масштабируются между 0 и 1, действуют как обратная альфа. То есть цвет заливки окрашен, как если бы он имел альфа-значение (1 - MaskSampleValue). Например, если значение образца 8-разрядной маски масштабируется до 0,8, текущий цвет заливки окрашивается, как если бы он имел значение альфа 0,2, то есть (1-0,8).

Я предполагаю, что функция переинтерпретирует ваши данные RGB в этом другом формате, что искажает значения цвета. Вы пытались напрямую использовать маску CGImage?

Быстрое редактирование: что я подразумеваю под "напрямую", это просто написать

+ (UIImage*)maskImage:(UIImage*)image withMask:(UIImage*)maskImage
{
    CGImageRef masked = CGImageCreateWithMask([image CGImage], [maskImage CGImage]);
    return [UIImage imageWithCGImage:masked];
}

Ответ 4

Для меня работали следующие строки кода

    +(UIImage*)maskImageExt:(UIImage *)image withMask:(UIImage *)maskImage {
      CGImageRef maskRef = maskImage.CGImage;
      CGImageRef imageRef = image.CGImage;

      CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                    CGImageGetHeight(maskRef),
                                    CGImageGetBitsPerComponent(maskRef),
                                    CGImageGetBitsPerPixel(maskRef),
                                    CGImageGetBytesPerRow(maskRef),
                                    CGImageGetDataProvider(maskRef), NULL, true);

CGImageRef maskImageRef = CGImageCreateWithMask([image CGImage], mask);

CGContextRef context = CGBitmapContextCreate(nil,
                                             CGImageGetWidth(imageRef),
                                             CGImageGetHeight(imageRef),
                                             CGImageGetBitsPerComponent(imageRef),
                                             CGImageGetBytesPerRow(imageRef),
                                             CGImageGetColorSpace(imageRef),
                                             CGImageGetBitmapInfo(imageRef));
CGRect imageRect = CGRectMake(0, 0, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
CGContextDrawImage(context, imageRect, maskImageRef);
CGImageRef maskedImageRef = CGBitmapContextCreateImage(context);
UIImage *maskedImage = [UIImage imageWithCGImage:maskedImageRef];

CGImageRelease(mask);
CGContextRelease(context);
CGImageRelease(maskedImageRef);

return maskedImage;

}

Ответ 5

Посмотрите, работает ли это лучше:

+ (UIImage*)maskImage:(UIImage*)image withMask:(UIImage*)maskImage {
   UIGraphicsBeginImageContext(image.size);
   CGImageRef maskRef = maskImage.CGImage;
   CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), CGImageGetHeight(maskRef), CGImageGetBitsPerComponent(maskRef), CGImageGetBitsPerPixel(maskRef), CGImageGetBytesPerRow(maskRef), CGImageGetDataProvider(maskRef), NULL, false);
   CGImageRef masked = CGImageCreateWithMask(image.CGImage, mask);
   UIImage* result = [UIImage imageWithData:UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext())];
   UIGraphicsEndImageContext();
   CGImageRelease(mask);
   CGImageRelease(masked);
   return result;
}

Ответ 6

Дэйв, я слышал о изображениях PNG с альфа-каналом, которые могут повлиять на такой код.

Я просто искал PNG Alpha Channel и придумал эту ссылку: текст ссылки

Итак, убедитесь, что PNG, который вы используете, имеет правильно настроенный альфа-канал

Ответ 7

Вы НЕ МОЖЕТЕ создать изображение любого типа с основной графикой, у которой нет альфа-канала.