// TestImageInterpolation.m
// Checks NSImage interpolation by scaling up a two-color image and counting its unique colors:
// InterpolationNone should have the same number of colors as the original image (2),
// InterpolationLow >= 2,
// InterpolationHigh >= InterpolationLow, 
// and InterpolationHigh >= InterpolationDefault >= InterpolationNone)

#import <AppKit/AppKit.h>


@implementation NSImage (TestImageInterpolation)

- (NSBitmapImageRep *) scaledBitmapOfSize: (NSSize) scaledSize
                        imageInterpolation: (NSImageInterpolation) imageInterpolation
{
    NSImage *scaledImage;
    NSRect imageBounds, scaledImageBounds;
    NSBitmapImageRep *scaledBitmap;

    scaledImage = [[[NSImage alloc] initWithSize: scaledSize] autorelease];
    
    if (!scaledImage)
        goto ERROR;

    imageBounds.origin = NSZeroPoint;
    imageBounds.size = [self size];

    scaledImageBounds.origin = NSZeroPoint;
    scaledImageBounds.size = scaledSize;

    [scaledImage lockFocus];

    [[NSGraphicsContext currentContext] setImageInterpolation: imageInterpolation];

    [self drawInRect: scaledImageBounds
            fromRect: imageBounds
            operation: NSCompositeCopy
            fraction: 1.0];

    scaledBitmap = 
        [[[NSBitmapImageRep alloc] initWithFocusedViewRect: scaledImageBounds] autorelease];

    [scaledImage unlockFocus];

    return scaledBitmap;

ERROR:
    return nil;
}

@end

@implementation NSBitmapImageRep (TestImageInterpolation)

- (int) numUniquePixelValues
{
    NSMutableSet *uniquePixelValuesSet;
    unsigned char *bitmapDataRow;
    int pixelsPerRow, bytesPerRow, rowCounter, pixelCounter;
    uint32_t *bitmapPixel;
    NSNumber *pixelValueNumber;

    if (([self samplesPerPixel] != 4) || ([self bitsPerSample] != 8))
    {
        goto ERROR;
    }

    uniquePixelValuesSet = [[[NSMutableSet alloc] init] autorelease];

    if (!uniquePixelValuesSet)
        goto ERROR;

    bitmapDataRow = [self bitmapData];

    if (!bitmapDataRow)
        goto ERROR;

    pixelsPerRow = [self pixelsWide];
    bytesPerRow = [self bytesPerRow];

    rowCounter = [self pixelsHigh];

    while (rowCounter--)
    {
        bitmapPixel = (uint32_t *) bitmapDataRow;

        pixelCounter = pixelsPerRow;

        while (pixelCounter--)
        {
            pixelValueNumber = [NSNumber numberWithUnsignedInt: *bitmapPixel];

            if (!pixelValueNumber)
                goto ERROR;

            [uniquePixelValuesSet addObject: pixelValueNumber];

            bitmapPixel++;
        }

        bitmapDataRow += bytesPerRow;
    }

    return [uniquePixelValuesSet count];

ERROR:
    return 0;
}

@end

int main()
{
    NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init];
    NSApplication *app; 
    app = [NSApplication sharedApplication];

    uint32_t twoPixelBitmapData[2] = {0, -1};
    unsigned char *twoPixelBitmapDataPlanes[1] = {(unsigned char *) &twoPixelBitmapData[0]};
    NSBitmapImageRep *twoColorBitmap, *scaledBitmap;
    NSImage *twoColorImage;
    NSSize scaledBitmapSize = {6, 1};
    int numUninterpolatedColors, numLowInterpolatedColors, numHighInterpolatedColors,
        numDefaultInterpolatedColors;

    twoColorBitmap = 
        [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: twoPixelBitmapDataPlanes
                                    pixelsWide: 2
                                    pixelsHigh: 1
                                    bitsPerSample: 8
                                    samplesPerPixel: 4
                                    hasAlpha: YES
                                    isPlanar: NO
                                    colorSpaceName: NSDeviceRGBColorSpace
                                    bytesPerRow: 8
                                    bitsPerPixel: 0]
                                autorelease];

    twoColorImage = [[[NSImage alloc] initWithSize: NSMakeSize(2,1)] autorelease];

    if (!twoColorBitmap || !twoColorImage)
    {
        goto EXIT;
    }

    [twoColorImage addRepresentation: twoColorBitmap];


    // NSImageInterpolationNone check: scaled two-color image should have 2 colors

    scaledBitmap = [twoColorImage scaledBitmapOfSize: scaledBitmapSize
                                    imageInterpolation: NSImageInterpolationNone];

    numUninterpolatedColors = [scaledBitmap numUniquePixelValues];

    if (numUninterpolatedColors != 2)
    {
        NSLog(@"ERROR: Failed image interpolation check using NSImageInterpolationNone - "
                "color count should be 2 when scaling a two-color image, actual count: %d", 
                numUninterpolatedColors);

        goto EXIT;
    }


    // NSImageInterpolationLow check: scaled two-color image should have 2 or more colors

    scaledBitmap = [twoColorImage scaledBitmapOfSize: scaledBitmapSize
                                    imageInterpolation: NSImageInterpolationLow];

    numLowInterpolatedColors = [scaledBitmap numUniquePixelValues];

    if (numLowInterpolatedColors < 2)
    {
        NSLog(@"ERROR: Failed image interpolation check using NSImageInterpolationLow - "
                "color count should be >= 2 when interpolating a two-color image, actual count: %d", 
                numLowInterpolatedColors);

        goto EXIT;
    }


    // NSImageInterpolationHigh check: scaled two-color image should have at least as many
    // colors as NSImageInterpolationLow

    scaledBitmap = [twoColorImage scaledBitmapOfSize: scaledBitmapSize
                                    imageInterpolation: NSImageInterpolationHigh];

    numHighInterpolatedColors = [scaledBitmap numUniquePixelValues];

    if (numHighInterpolatedColors < numLowInterpolatedColors)
    {
        NSLog(@"ERROR: Failed image interpolation check using NSImageInterpolationHigh - "
                "color count (%d) is less than with NSImageInterpolationLow (%d)",
                numHighInterpolatedColors, numLowInterpolatedColors);

        goto EXIT;
    }


    // NSImageInterpolationDefault check: scaled two-color image should have at least as many
    // colors as NSImageInterpolationNone and no more than NSImageInterpolationHigh

    scaledBitmap = [twoColorImage scaledBitmapOfSize: scaledBitmapSize
                                    imageInterpolation: NSImageInterpolationDefault];

    numDefaultInterpolatedColors = [scaledBitmap numUniquePixelValues];

    if ((numDefaultInterpolatedColors < numUninterpolatedColors)
        || (numDefaultInterpolatedColors > numHighInterpolatedColors))
    {
        NSLog(@"ERROR: Failed image interpolation check using NSImageInterpolationDefault - "
                "color count (%d) was not between that of NSImageInterpolationNone (%d) and "
                "NSImageInterpolationHigh (%d)", numDefaultInterpolatedColors, 
                numUninterpolatedColors, numHighInterpolatedColors);

        goto EXIT;
    }


    // Successfully passed interpolation tests

    NSLog(@"PASSED image interpolation checks - color counts for scaling a two-color image with "
            "interpolation settings: None: %d, Low: %d, High: %d, Default: %d",
            numUninterpolatedColors, numLowInterpolatedColors, numHighInterpolatedColors,
            numDefaultInterpolatedColors);

EXIT:
    [autoreleasePool release];
    
    return 0;
}

