Любая идея, почему этот код маскировки изображения не работает? - PullRequest
10 голосов
/ 15 июля 2009

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

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

Я создаю оба изображения как 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 остается полностью без изменений. Никакой маскировки не происходит. Но теперь странная вещь: если я переверну это, то есть использую это изображение в качестве маски, а маску в качестве цветного изображения в маску, то я получу нечто очень уродливое в оттенках серого (но замаскированное;)). 1013 *

Есть идеи, что случилось с моим кодом?

ОБНОВЛЕНИЕ: я просто гуглил другой ч / б png, чтобы использовать его в качестве маски. И тогда этот работал! Но тот, который я сделал сам, не работает. Поэтому я предполагаю, что в коде есть большие проблемы с декодированием изображений. Мне бы пришлось «нормализовать» изображения к определенному формату, чтобы он работал.

Ответы [ 7 ]

6 голосов
/ 21 июля 2012

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

- (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];

}

см. пример демонстрации

5 голосов
/ 23 июля 2010

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

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

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

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

CGImageRef createMaskWithImage(CGImageRef image)
{
    int maskWidth               = CGImageGetWidth(image);
    int maskHeight              = CGImageGetHeight(image);
    //  round bytesPerRow to the nearest 16 bytes, for performance's 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 голосов
/ 21 октября 2009

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];
}
1 голос
/ 13 июля 2016

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

    +(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;

}

0 голосов
/ 23 февраля 2012

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

0 голосов
/ 14 октября 2009

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

Я только что гуглил альфа-канал PNG и нашел эту ссылку: текст ссылки

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

0 голосов
/ 15 июля 2009

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

+ (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;
}
...