CGImageRef поврежден после возвращения из метода - PullRequest
0 голосов
/ 27 января 2020

Мой код создает TIFF-представление изображения, и я хочу перекодировать его во что-то другое. Это не проблема c.

Моя функция ImgUtils:

+ (CGImageRef) processImageData:(NSData*)rep {

    NSBitmapImageRep *bitmapRep = [NSBitmapImageRep imageRepWithData:rep];

    int width = bitmapRep.size.width;
    int height = bitmapRep.size.height;
    size_t pixels_size = width * height;
    Byte raw_bytes[pixels_size * 3];

    //
    //  processing, creates and stores raw byte stream
    //

    int bitsPerComponent = 8;
    int bytesPerPixel = 3;
    int bitsPerPixel = bytesPerPixel * bitsPerComponent;
    int bytesPerRow = bytesPerPixel * width;

    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL,
                                                              raw_bytes,
                                                              pixels_size * bytesPerPixel,
                                                              NULL);

    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;

    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
    CGImageRef imageRef = CGImageCreate(width,
                                        height,
                                        bitsPerComponent,
                                        bitsPerPixel,
                                        bytesPerRow,
                                        colorSpaceRef,
                                        bitmapInfo,
                                        provider,
                                        NULL,
                                        NO,
                                        renderingIntent);


    [ImgUtils saveToPng:imageRef withSuffix:@"-ok"];

    CGColorSpaceRelease(colorSpaceRef);
    CGDataProviderRelease(provider);

    return imageRef;
}

Существует еще один метод, который сохраняет CGImageRef в файловую систему.

+ (BOOL) saveToPng:(CGImageRef)imageRef withSuffix:(NSString*)suffix {
    CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:[NSString stringWithFormat:@"~/Downloads/pic%@.png", suffix]];
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypePNG, 1, NULL);
    CGImageDestinationAddImage(destination, imageRef, nil);
    CGImageDestinationFinalize(destination);
    CFRelease(destination);
    return YES;
}

Как видите, сразу после обработки изображение, я сохраняю его на диске, как pic-ok.png.

Вот код, который вызывает функцию обработки:

 CGImageRef cgImage = [ImgUtils processImageData:imageRep];
 [ImgUtils saveToPng:cgImage withSuffix:@"-bad"];

Проблема в том, что два изображения различаются. Второй с суффиксом -bad поврежден. Смотрите примеры ниже. Похоже, что область памяти, на которую указывает указатель CGImageRef, освобождается и перезаписывается сразу после возврата из метода.

pic-ok.png pic-bad.png

Я тоже пробовал return CGImageCreateCopy(imageRef); но ничего не изменилось.

Чего мне не хватает?

1 Ответ

2 голосов
/ 28 января 2020

CGDataProviderCreateWithData() не копирует предоставленный вами буфер. Его цель - разрешить создание поставщика данных, который напрямую обращается к этому буферу.

Ваш буфер создается в стеке. Он становится недействительным после +processImageData: возврата. Однако CGImage по-прежнему ссылается на провайдера, а провайдер по-прежнему ссылается на недопустимый буфер.

Одним из решений было бы создание буфера в куче и предоставление обратного вызова через параметр releaseData, который освобождает Это. Другой вариант - создать CFData из буфера (который его копирует), а затем создать поставщика данных, используя CGDataProviderCreateWithCFData(). Вероятно, лучше всего было бы создать CFMutableData требуемой емкости, установить его длину в соответствии и использовать его хранилище (CFDataGetMutableBytePtr()) в качестве буфера с самого начала. Он распределяется в куче, управляется памятью и не требует копирования.

...