1

我正在尝试使用图像的原始像素,但遇到了一些问题。

首先,在 C4Image 上调用 .CGImage 不起作用,所以我必须使用 UIImage 来加载文件。

其次,字节数组似乎是错误的长度,图像似乎没有正确的尺寸或颜色。

我从这里的讨论中借用了一些代码。

UIImage *image      = [UIImage imageNamed:@"C4Table.png"];
CGImageRef imageRef = image.CGImage;
NSData *data        = (__bridge NSData *)CGDataProviderCopyData(CGImageGetDataProvider(imageRef));
unsigned char * pixels        = (unsigned char *)[data bytes];

for(int i = 0; i < [data length]; i += 4) {
    pixels[i] = 0; // red
    pixels[i+1] = pixels[i+1]; // green
    pixels[i+2] = pixels[i+2]; // blue
    pixels[i+3] = pixels[i+3]; // alpha
}

size_t imageWidth                    = CGImageGetWidth(imageRef);
size_t imageHeight                   = CGImageGetHeight(imageRef);
NSLog(@"width:   %d  height: %d  datalength: %d" ,imageWidth ,imageHeight, [data length] );

C4Image *imgimgimg = [[C4Image alloc] initWithRawData:pixels width:imageWidth height:imageHeight];
[self.canvas addImage:imgimgimg];

有没有更好的方法来做到这一点,还是我错过了一步?

4

1 回答 1

1

Close. There is a loadPixelData method on C4Image, and if you check in the main C4 repo (C4iOS) you'll be able to see how the image class loads pixels... It can be tricky.

C4Image loadPixelData:

-(void)loadPixelData {
    const char *queueName = [@"pixelDataQueue" UTF8String];
    __block dispatch_queue_t pixelDataQueue = dispatch_queue_create(queueName,  DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(pixelDataQueue, ^{
        NSUInteger width = CGImageGetWidth(self.CGImage);
        NSUInteger height = CGImageGetHeight(self.CGImage);
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

        bytesPerPixel = 4;
        bytesPerRow = bytesPerPixel * width;
        free(rawData);
        rawData = malloc(height * bytesPerRow);

        NSUInteger bitsPerComponent = 8;
        CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
        CGColorSpaceRelease(colorSpace);
        CGContextDrawImage(context, CGRectMake(0, 0, width, height), self.CGImage);
        CGContextRelease(context);
        _pixelDataLoaded = YES;
        [self postNotification:@"pixelDataWasLoaded"];
        pixelDataQueue = nil;
    });
}

To modify this for your question, I have done the following:

-(void)getRawPixelsAndCreateImages {
    C4Image *image      = [C4Image imageNamed:@"C4Table.png"];

    NSUInteger width = CGImageGetWidth(image.CGImage);
    NSUInteger height = CGImageGetHeight(image.CGImage);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    unsigned char *rawData = malloc(height * bytesPerRow);

    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.CGImage);
    CGContextRelease(context);

    C4Image *imgimgimg = [[C4Image alloc] initWithRawData:rawData width:width height:height];
    [self.canvas addImage:imgimgimg];

    for(int i = 0; i < height * bytesPerRow; i += 4) {
        rawData[i] = 255;
    }

    C4Image *redImgimgimg = [[C4Image alloc] initWithRawData:rawData width:width height:height];
    redImgimgimg.origin = CGPointMake(0,320);
    [self.canvas addImage:redImgimgimg];
}

It can be quite confusing to learn how to work with pixel data, because you need to know how to work with Core Foundation (which is pretty much a C api). The main line of code, to populate the rawData is a call to CGContextDrawImage which basically copies the pixels from an image into the data array that you're going to play with.

I have created a gist that you can download to play around with in C4.

Working with Raw Pixels

In this gist you'll see that I actually grab the CGImage from a C4Image object, use that to populate an array of raw data, and then use that array to create a copy of the original image. Then, I modify the red component of the pixel data by changing all values to 255, and then use the modified pixel array to create a tinted version of the original image.

于 2013-02-21T01:00:49.237 回答