Могу ли я редактировать пиксели свойства UIImage CGImage
UIImage имеет свойство только для чтения CGImage. Я должен прочитать его пиксели в блок памяти и отредактировать их, а затем создать новый UIImage, чтобы заменить старый. Я хочу знать, есть ли способ обойти свойство только для чтения и редактировать эти пиксели напрямую.
Благодарю.
Спасибо всем. Я нашел способ сделать это. Напишите класс с этим методом:
-(void)preProcess:(UIImage*)srcImage {
m_Context = ...// Created by calling CGBitmapContextCreate(...)
...
CGContextDrawImage(m_Context, rect, srcImage.CGImage);
m_Bits = (unsigned char*)CGBitmapContextGetData (mContext);
}
-(void)postProcess {
CGContextRelease(m_Context);
free(m_Bits);
}
-(UIImage*)doProcess:(CGPoint)pt {// just a example
unsigned char* ppxl = m_Bits + ...
// do something...
CGImageRef imRef = CGBitmapContextCreateImage(mContext);
return [UIImage imageWithCGImage:imRef];
}
И preProcess и postProcess вызываются только один раз.
7 ответов
Это может помочь вам.
Когда вы закончите, вы можете использовать CGImageCreate
создать CGImageRef, затем использовать +[UIImage imageWithCGImage:]
создать новый UIImage.
Для более тупых среди нас (читай: будущий я) вот рабочий код, основанный на ответах Итай и Дейва Р. Он начинается с UIImage и заканчивается измененным UIImage:
// load image
UIImage *image = [UIImage imageNamed:@"test.png"];
CGImageRef imageRef = image.CGImage;
NSData *data = (NSData *)CGDataProviderCopyData(CGImageGetDataProvider(imageRef));
char *pixels = (char *)[data bytes];
// this is where you manipulate the individual pixels
// assumes a 4 byte pixel consisting of rgb and alpha
// for PNGs without transparency use i+=3 and remove int a
for(int i = 0; i < [data length]; i += 4)
{
int r = i;
int g = i+1;
int b = i+2;
int a = i+3;
pixels[r] = 0; // eg. remove red
pixels[g] = pixels[g];
pixels[b] = pixels[b];
pixels[a] = pixels[a];
}
// create a new image from the modified pixel data
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
size_t bitsPerPixel = CGImageGetBitsPerPixel(imageRef);
size_t bytesPerRow = CGImageGetBytesPerRow(imageRef);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, [data length], NULL);
CGImageRef newImageRef = CGImageCreate (
width,
height,
bitsPerComponent,
bitsPerPixel,
bytesPerRow,
colorspace,
bitmapInfo,
provider,
NULL,
false,
kCGRenderingIntentDefault
);
// the modified image
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
// cleanup
free(pixels);
CGImageRelease(imageRef);
CGColorSpaceRelease(colorspace);
CGDataProviderRelease(provider);
CGImageRelease(newImageRef);
Вы не можете получить в исходных пикселях. Тем не менее, вы можете получить копию. Один из вариантов - сделать то, что предложил Мэтт, и преобразовать его в PNG/JPG - хотя помните, что изображение теперь сжато, и вы будете манипулировать сжатым файлом, а не пикселями напрямую.
Если вы хотите получить копию необработанных пикселей, вы можете сделать что-то вроде:
UIImage* image = ...; // An image
NSData* pixelData = (NSData*) CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
void* pixelBytes = [pixelData bytes];
// Take away the red pixel, assuming 32-bit RGBA
for(int i = 0; i < [pixelData length]; i += 4) {
bytes[i] = 0; // red
bytes[i+1] = bytes[i+1]; // green
bytes[i+2] = bytes[i+2]; // blue
bytes[i+3] = bytes[i+3]; // alpha
}
Теперь, если вы хотите превратить это в новый UIImage, вы можете сделать что-то вроде:
NSData* newPixelData = [NSData dataWithBytes:pixelBytes length:[pixelData length]];
UIImage* newImage = [UIImage imageWithData:newPixelData]; // Huzzah
Я использовал следующий код, чтобы добавить 2 тонкие красные линии справа и слева от изображения
-(UIImage*)ModifyImage:(UIImage*) img
{
UIGraphicsBeginImageContext(img.size);
[img drawInRect:CGRectMake(0,0,img.size.width,img.size.height) blendMode:kCGBlendModeSourceOut alpha:1.0f];
CGContextRef ctx = UIGraphicsGetCurrentContext();
int w =img.size.width;
int cw,ch;
cw = img.size.width / 35;
ch = img.size.height / 35;
unsigned char* data = CGBitmapContextGetData (ctx);
for(int y = 0 ; y < img.size.height ; y++)
{
for(int x = 0 ; x < img.size.width ; x++)
{
//int offset = 4*((w * y) + x);
int offset = (CGBitmapContextGetBytesPerRow(ctx)*y) + (4 * x);
int blue = data[offset];
int green = data[offset+1];
int red = data[offset+2];
//int alpha = data[offset+3];
if(x <= (cw * 2) || x >= (cw * 35))
{
data[offset] = 0;
data[offset+1] = 0;
data[offset+2] = 255;
data[offset+3] = 255;
}
}
}
UIImage *rtimg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return rtimg;
}
Краткий ответ: нет. Тем не менее, вы говорите, что все равно должны сделать копию, так почему бы просто не получить объект NSData и манипулировать его байтами.
Из документов Apple на UIImage:
Поскольку объекты изображений являются неизменяемыми, они также не обеспечивают прямой доступ к данным, лежащим в их основе. Однако вы можете получить объект NSData, содержащий представление данных изображения в формате PNG или JPEG, используя функции UIImagePNGRepresentation и UIImageJPEGRepresentation.
Чтобы получить данные в формате PNG, используйте:
NSData * UIImagePNGRepresentation (
UIImage *image
);
для JPEG используйте:
NSData * UIImageJPEGRepresentation (
UIImage *image,
CGFloat compressionQuality
);
Измените строку данных NSData *, в ответе Шона, на эту, и она отлично работает в iOS7!
NSData *data = (NSData *)CFBridgingRelease(CGDataProviderCopyData(CGImageGetDataProvider(imageRef)));
@shaun Сообщение Инмана было единственной работой, которую я нашел в Интернете до сих пор! БЛАГОДАРЮ ВАС! Однако, похоже, что, по крайней мере, в IOS3 цвета PNG сохраняются несколько иначе, чем вы заявили, вот что сработало для меня (только для PNG!):
for(int i = 0; i < [data length]; i += 4) {
pixels[i+0] = 0; // eg. alpha?
pixels[i+1] = 0; // eg. red!
pixels[i+2] = 0; // eg. green!
pixels[i+3] = pixels[i+3]; // eg. blue!
}
Было бы здорово, если бы кто-нибудь смог найти способ, который бы работал для любого типа файла!