2009-07-15 4 views
10

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

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

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

ответ

0

Смотрите, если он работает лучше любой этот путь:

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

Хотя это выглядит красиво, в моем случае он просто делает изображение полностью прозрачным. См. Мое обновление выше. Я понял что-то странное. – Thanks

+1

Я использовал вариант на приведенном выше коде с масками, созданными в Photoshop, преобразованными в «Оттенки серого» и экспортированными как 24-битные PNG. – Ramin

+0

Если вы хотите использовать вышеуказанный код, убедитесь, что ваши файлы изображений, содержащие маску, являются 24-разрядными PNG, которые не имеют альфа-канала. Pixelmator, например, не сообщает вам эту информацию. Вам нужно использовать Photoshop или Gimp. –

0

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

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

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

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]; 
} 
5

Как вы узнали, как вы сохраните файл может иметь значение, так как 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; 
} 
-6

Вы не можете создать образ любого рода, с графическим ядром, которые не имеют альфа-канал.

+2

Это точно неправильно. Ты можешь. – awolf

6

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

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

} 

передать этот example demonstration

+7

Это работает до тех пор, пока полученный UIImage отображается с использованием UIImageView или врисован в новый контекст изображения вручную. Если вы попытаетесь сохранить изображение в файл, используя UIImagePNGRпредставление (yourMaskedImage), вы потеряете маску. Просто FYI - я немного потянул свои волосы за это. Также в конце вашего кода вы должны высвободить некоторые ссылки, чтобы избежать утечек памяти: CGImageRelease (maskedImageRef); CGImageRelease (маска); –

+0

Алексей комментарий украинца помогает много, спасибо! – Chengjiong

+0

Впущенные часы и комментарий @ AlextheUkrainian был ответом. Спасибо огромное! – mxcl

1

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

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

}

Смежные вопросы