Question

I'm writing an image editing programme, and I need functionality to dither any arbitrary 24-bit RGB image (I've taken care of loading it with CoreGraphics and such) to an image with 3 bit colour channels, then displaying it. I've set up my matrices and such, but I've not got any results from the code below besides a simple pattern that is applied to the image:

- (CGImageRef) ditherImageTo16Colours:(CGImageRef)image withDitheringMatrixType:(SQUBayerDitheringMatrix) matrix {
    if(image == NULL) {
        NSLog(@"Image is NULL!");
        return NULL;
    }

    unsigned int imageWidth = CGImageGetWidth(image);
    unsigned int imageHeight = CGImageGetHeight(image);

    NSLog(@"Image size: %u x %u", imageWidth, imageHeight);

    CGContextRef context = CGBitmapContextCreate(NULL, 
                                                 imageWidth, 
                                                 imageHeight, 
                                                 8, 
                                                 4 * (imageWidth), 
                                                 CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), 
                                                 kCGImageAlphaNoneSkipLast);

    CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), image); // draw it
    CGImageRelease(image); // get rid of the image, we don't want it anymore.


    unsigned char *imageData = CGBitmapContextGetData(context);

    unsigned char ditheringModulusType[0x04] = {0x02, 0x03, 0x04, 0x08};
    unsigned char ditheringModulus = ditheringModulusType[matrix];

    unsigned int red;
    unsigned int green;
    unsigned int blue;

    uint32_t *memoryBuffer;
    memoryBuffer = (uint32_t *) malloc((imageHeight * imageWidth) * 4);

    unsigned int thresholds[0x03] = {256/8, 256/8, 256/8};

    for(int y = 0; y < imageHeight; y++) {
        for(int x = 0; x < imageWidth; x++) {
            // fetch the colour components, add the dither value to them
            red = (imageData[((y * imageWidth) * 4) + (x << 0x02)]);
            green = (imageData[((y * imageWidth) * 4) + (x << 0x02) + 1]);
            blue = (imageData[((y * imageWidth) * 4) + (x << 0x02) + 2]);

            if(red > 36 && red < 238) {
                red += SQUBayer117_matrix[x % ditheringModulus][y % ditheringModulus];
            } if(green > 36 && green < 238) {
                green += SQUBayer117_matrix[x % ditheringModulus][y % ditheringModulus];
            } if(blue > 36 && blue < 238) {
                blue += SQUBayer117_matrix[x % ditheringModulus][y % ditheringModulus];
            }

//            memoryBuffer[(y * imageWidth) + x] = (0xFF0000 + ((x >> 0x1) << 0x08) + (y >> 2));
            memoryBuffer[(y * imageWidth) + x] = find_closest_palette_colour(((red & 0xFF) << 0x10) | ((green & 0xFF) << 0x08) | (blue & 0xFF));
        }
    }

    //CGContextRelease(context);
    context = CGBitmapContextCreate(memoryBuffer, 
                                    imageWidth, 
                                    imageHeight, 
                                    8, 
                                    4 * (imageWidth), 
                                    CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), 
                                    kCGImageAlphaNoneSkipLast);

    NSLog(@"Created context from buffer: %@", context);

    CGImageRef result = CGBitmapContextCreateImage(context);
    return result;
}

Note that find_closest_palette_colour doesn't do anything besides returning the original colour right now for testing.

I'm trying to implement the example pseudocode from Wikipedia, and I don't really get anything out of that right now.

Anyone got a clue on how to fix this up?

Was it helpful?

Solution

Use the code that I have provided here: https://stackoverflow.com/a/17900812/342646

This code converts the image to a single-channel gray-scale first. If you want the dithering to be done on a three-channel image, you can just split your image into three channels and call the function three times (once per channel).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top