Альфа-маска Процесс извлечения Цель C реализация - PullRequest
2 голосов
/ 09 декабря 2011

Есть ли у вас реализация Objective C, эквивалентная команде ImageMagick:

convert -alpha Extract -type optimize -strip -quality 60 +dither Source.png Alpha.jpg

Мне не удалось найти решение прямо сейчас. Я ищу фрагмент AlphaExtractor, который извлекает альфа из png и сохраняет его в JPG Grayscale

Маска создана с использованием фрагмента кода:

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;

    //  we use CFData instead of malloc(), because the memory has to stick around
    //  for the lifetime of the mask. if we used malloc(), we'd have to
    //  tell the CGDataProvider how to dispose of the memory when done. using
    //  CFData is just easier and cleaner.

    CFMutableDataRef dataBuffer = CFDataCreateMutable(kCFAllocatorDefault, 0);
    CFDataSetLength(dataBuffer, bufferSize);

    //  the data will be 8 bits per pixel, no alpha
    CGColorSpaceRef colorSpace  = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);//CGColorSpaceCreateDeviceGray();
    CGContextRef ctx            = CGBitmapContextCreate(CFDataGetMutableBytePtr(dataBuffer),
                                                        maskWidth, maskHeight,
                                                        8, bytesPerRow, colorSpace, 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(colorSpace);
    CFRelease(dataBuffer);

    return mask;
}

и сохранено:

-(void)_saveJPEGImage:(CGImageRef)imageRef path:(NSString *)path {

    NSURL *fileURL = [NSURL fileURLWithPath:path]; 
    CFURLRef fileUrlRef=(CFURLRef)fileURL;

    CFMutableDictionaryRef mSaveMetaAndOpts = CFDictionaryCreateMutable(nil, 0, &kCFTypeDictionaryKeyCallBacks,  &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(mSaveMetaAndOpts, kCGImageDestinationLossyCompressionQuality, [NSNumber numberWithFloat:0.7]); // set the compression quality here
    CFDictionarySetValue(mSaveMetaAndOpts, kCGImageDestinationBackgroundColor, kCGColorClear);

    CGImageDestinationRef dr = CGImageDestinationCreateWithURL (fileUrlRef, kUTTypeJPEG , 1, NULL);
    CGImageDestinationAddImage(dr, imageRef, mSaveMetaAndOpts);
    CGImageDestinationFinalize(dr);
    CFRelease(dr);
}

Ответы [ 2 ]

1 голос
/ 10 декабря 2011

Очень быстрое грязное рабочее решение:

Предполагая, что у нас есть 32-байтовые необработанные данные (если не код должен быть адаптирован)

1 - мы перебираем байты с шагом +4 и изменяем компоненты r, g, b.

 CGImageRef ref=CGImageCreateCopy([_imageView image]);
NSData *data        = (NSData *)CGDataProviderCopyData(CGImageGetDataProvider(ref));
char   *bytes       = (char *)[data bytes];

int i;
for( i= 0; i < [data length]; i += 4)
{
    int r = i;
    int g = i+1;
    int b = i+2;
    int a = i+3;

    bytes[r]   = 0; 
    bytes[g]   = 0;
    bytes[b]   = 0;
    bytes[a]   = bytes[a];
}

2 - Мы создаем новую ссылку на изображение RGBA (32Bit) с «измененными данными»:

size_t width                    = CGImageGetWidth(ref);
size_t height                   = CGImageGetHeight(ref);
size_t bitsPerComponent         = CGImageGetBitsPerComponent(ref);
size_t bitsPerPixel             = CGImageGetBitsPerPixel(ref);
size_t bytesPerRow              = CGImageGetBytesPerRow(ref);

CGColorSpaceRef colorspace      = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo         = CGImageGetBitmapInfo(ref);
CGDataProviderRef provider      = CGDataProviderCreateWithData(NULL,bytes, [data length], NULL);

CGImageRef newImageRef = CGImageCreate (
                                        width,
                                        height,
                                        bitsPerComponent,
                                        bitsPerPixel,
                                        bytesPerRow,
                                        colorspace,
                                        bitmapInfo,
                                        provider,
                                        NULL,
                                        false,
                                        kCGRenderingIntentDefault
                                        );

3- Мы сохраняем эту новую ссылку на изображение размером 32 байта в файл JPEG. Сгенерированный JPG будет использоваться в качестве маски.

Мы могли бы сделать это более чистым способом, создав 8-битный контекст и написав только «альфа-компонент».

0 голосов
/ 09 декабря 2011

Я вижу две проблемы:

CGContextDrawImage(ctx, CGRectMake(0, 0, maskWidth, maskHeight), image);

не извлекает альфу, он просто альфа-композитизирует изображение на черном фоне. Если изображение чёрное с прозрачностью, то ожидаемый результат будет полностью чёрным.

и

CGImageRef mask = CGImageMaskCreate(maskWidth, maskHeight, 8, 8, bytesPerRow,
                                    dataProvider, NULL, FALSE);

Вы рассматриваете созданную вами маску как реальное изображение. Если вы замените эту строку на

CGImageRef mask = CGImageCreate(maskWidth, maskHeight, 8, 8, bytesPerRow, colorSpace, 0,
                                dataProvider, NULL, FALSE, kCGRenderingIntentDefault);

Тогда вы получите версию изображения в оттенках серого (см. Задачу 1)

...