Я надеюсь закончить тем, что Core Graphics CGImageRef рисуется на экране в переопределенном — (void) drawRect: (CGRect) — методе rect. Вот что у меня так далеко.
- (void)drawRect:(CGRect)rect
{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
const CGFloat _x = CGRectGetMinX(rect);
const CGFloat _y = CGRectGetMinY(rect);
const CGFloat _w = CGRectGetWidth(rect);
const CGFloat _h = CGRectGetHeight(rect);
const CGFloat scale = [[UIScreen mainScreen] scale];
const int pixelsWide = (_w * scale);
const int pixelsHigh = (_h * scale);
const size_t colorValues = 4;
const int rawMemorySize = (pixelsWide * pixelsHigh * colorValues);
// raw pixel data memory
UInt8 pixelData[rawMemorySize];
// fill the raw pixel buffer with arbitrary gray color for test
for(size_t ui = 0; ui < rawMemorySize; ui++)
{
pixelData[ui] = 255; // black
}
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CFDataRef rgbData = CFDataCreate(NULL, pixelData, rawMemorySize);
CGDataProviderRef provider = CGDataProviderCreateWithCFData(rgbData);
CGImageRef rgbImageRef = CGImageCreate(pixelsWide, pixelsHigh, 8, (colorValues * colorValues), (pixelsWide * colorValues), colorspace, kCGBitmapByteOrderDefault, provider, NULL, true, kCGRenderingIntentDefault);
CFRelease(rgbData);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorspace);
//Draw the bitmapped image
CGContextDrawImage(currentContext, CGRectMake(_x, _y, pixelsWide, 64), rgbImageRef);
CGImageRelease(rgbImageRef);
}
Я получил ошибку EXC_BAD_ACCESS в цикле for.
Я думаю, что я близко, но я не совсем уверен. Есть идеи, что может быть виновником? Заранее спасибо 🙂
Еще пара вещей, о которых нужно знать.
rect
Аргументом для drawRect является только грязный прямоугольник, который может быть меньше self.bounds
, использование self.bounds
если ваш код не оптимизирован для рисования только грязного прямоугольника.
Выделение pixelData
массив в стеке — плохая идея и может быть причиной ошибки. Все зависит от того, насколько велик вид. Я подозреваю, что AaronGolden использовал меньшее представление, чем вы, и, следовательно, не было никаких проблем. Безопаснее calloc
массив, и освободите его в конце после того, как вы закончите использовать его. Обратите внимание, что calloc
очистит массив до прозрачного черного цвета.
Вот пример кода, который я использовал для подобных вещей в прошлом. Хотя массив пикселей создается с calloc
вы по-прежнему можете обращаться к нему как к стандартному массиву (например, pixels[100] = 0xff0000ff;
совершенно верно). Однако из соображений производительности я обычно использую указатели для доступа к отдельным пикселям.
const CGFloat scale = [[UIScreen mainScreen] scale];
int width = self.bounds.size.width * scale;
int height = self.bounds.size.height * scale;
uint32_t *pixels = calloc( width * height, sizeof(uint32_t) );
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate( pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast );
uint8_t *bufptr = (uint8_t *)pixels;
for ( int y = 0; y < height; y++)
{
for ( int x = 0; x < width; x++ )
{
bufptr[0] = redValue;
bufptr[1] = greenValue;
bufptr[2] = blueValue;
bufptr[3] = alphaValue;
bufptr += 4;
}
}
CGImageRef newCGImage = CGBitmapContextCreateImage( context );
CGContextRelease( context );
CGColorSpaceRelease( colorSpace );
free( pixels );
Вот пара предложений. Я попробовал ваш код и не получил неправильный доступ в цикле for, как вы описали, но:
Вам не нужен цикл for, чтобы установить все на 255 таким образом. Ты можешь использовать memset
:
memset(pixelData, 255, sizeof(pixelData));
И в вашем вызове CGImageCreate аргумент сразу после вашего литерала 8 неверен. Это должно быть количество бит на пиксель, которое 8 * colorValues
не colorValues * colorValues
, Так что создайте свой образ как:
CGImageRef rgbImageRef = CGImageCreate(pixelsWide, pixelsHigh, 8, 8 * colorValues, pixelsWide * colorValues, colorspace, kCGBitmapByteOrderDefault, provider, NULL, true, kCGRenderingIntentDefault);
Наконец, я заметил, что вы добавили комментарий о том, что 255 соответствует черному, но это не так. Если вы сделаете все свои байты данных пикселей 255, ваше изображение должно быть заполнено белый. Вы рисуете ваше изображение с высотой 64 точки в вашем вызове CGContextDrawImage, и действительно я вижу белый бар 64 балла, когда я запускаю ваш код с этими исправлениями.