CGBitmapContextCreate возвращает значение null;запись массива пикселов rbga в файл - PullRequest
3 голосов
/ 14 декабря 2011

Я пытаюсь записать массив пикселей RBGA в файл, используя найденный код здесь [stackoverflow.com], но это не удается.

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

При запуске, метод ниже a) печатает, что мы не создали изображение (CGBitmapContextCreateImage(bitmapContext) вернул NULL) и b) умирает при попытке освободить изображение (RayTracerProject[33126] <Error>: CGBitmapContextCreateImage: invalid context 0x0 ImageIO: <ERROR> CGImageDestinationAddImage image parameter is nil), что имеет смысл, потому что cgImage нулевой.

Метод:

-(void) write{

char* rgba = (char*)malloc(width*height);
for(int i=0; i < width*height; ++i) {
    rgba[4*i] = (char)[Image red:pixels[i]];
    rgba[4*i+1] = (char)[Image green:pixels[i]];
    rgba[4*i+2] = (char)[Image blue:pixels[i]];
    rgba[4*i+3] = (char)[Image alpha:pixels[i]];
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bitmapContext = CGBitmapContextCreate(
                                                   rgba,
                                                   width,
                                                   height,
                                                   8, // bitsPerComponent
                                                   width, // bytesPerRow
                                                   colorSpace,
                                                   kCGImageAlphaNoneSkipLast);

CFRelease(colorSpace);

CGImageRef cgImage = CGBitmapContextCreateImage(bitmapContext);

if ( cgImage == NULL ) 
    printf("Couldn't create cgImage correctly"). 

CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("image.png"), kCFURLPOSIXPathStyle, false);

CFStringRef type = kUTTypePNG; // or kUTTypeBMP if you like
CGImageDestinationRef dest = CGImageDestinationCreateWithURL(url, type, 1, 0);

CGImageDestinationAddImage(dest, cgImage, 0);

CFRelease(cgImage);
CFRelease(bitmapContext);
CGImageDestinationFinalize(dest);
free(rgba);
}; 

Для полноты, мои методы сдвига битов:

// Extract the 8-bit red component from a 32bit color integer. 
+(int) red:(int) color{
 return (color >> 16) & 0xff;
};

// Extract the 8-bit green component from a 32bit color integer. 
+(int) green:(int) color{
  return (color >> 8) & 0xff;
};

// Extract the 8-bit blue component from a 32bit color integer. 
+(int) blue:(int) color{
  return (color & 0xff);
};

// Extract the 8-bit alpha component from a 32bit color integer. 
+(int) alpha:(int) color{
  return (color >> 24) & 0xff;
};

Согласно найденным документам здесь [developer.apple.com], CGBitmapContextCreateImage вернет A new bitmap context, or NULL if a context could not be created, но не поможет мне понять, почему не удалось создать контекст.

Что я делаю не так? [Кроме того, если есть намного более умный способ записи массива пикселей в файл в Objective-C, я не привязан к этому конкретному способу работы - этот проект является портом от Java, который я сделал несколько лет назад - Я использовал FileOutputStream, но не могу найти эквивалент в Objective-C].

1 Ответ

3 голосов
/ 15 декабря 2011

У меня это работает сейчас - публикуем это на тот случай, если кто-то еще найдет это полезным однажды.

Есть несколько ошибок с кодом выше - я не использовал width*4 для байтов на строку в вызове, например, CGBitmapContextCreate, и мой массив rgba был в 4 раза меньше, чем должен был иметь было. Приведенный ниже код работает, хотя я не знаю, куда изображение сохраняется (я собираюсь жестко закодировать путь, пока не выясню).

-(void) write{

 //printf("First pixel is: %d\n", pixels[0]);
 // RGBA array needs to be 4x pixel array - using 4bytes per int.  
 char* rgba = (char*)malloc(width*height*4);
 //printf("Size of char array: %d\n", width*height*4);

 for(int i=0; i < width*height; ++i) {
    rgba[4*i] = (char)[Image red:pixels[i]];
    rgba[4*i+1] = (char)[Image green:pixels[i]];
    rgba[4*i+2] = (char)[Image blue:pixels[i]];
    rgba[4*i+3] = (char)[Image alpha:pixels[i]];
 }
 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
 CGContextRef bitmapContext = CGBitmapContextCreate(
                                                   rgba,
                                                   width,
                                                   height,
                                                   8, // bitsPerComponent
                                                   width*4, // bytesPerRow (4x larger then width)
                                                   colorSpace,
                                                   kCGImageAlphaNoneSkipLast);

 CFRelease(colorSpace);

 CGImageRef cgImage = CGBitmapContextCreateImage(bitmapContext);

 /*if ( cgImage == NULL ) 
      printf("Couldn't create cgImage correctly");
  else
      printf("Has been created correctly");
 */
 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,  CFSTR("image.png"), kCFURLPOSIXPathStyle, false);

 CFStringRef type = kUTTypePNG; // or kUTTypeBMP if you like
 CGImageDestinationRef dest = CGImageDestinationCreateWithURL(url, type, 1, 0);

 CGImageDestinationAddImage(dest, cgImage, 0);

 CFRelease(cgImage);
 CFRelease(bitmapContext);
 CGImageDestinationFinalize(dest);
 free(rgba);
}; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...