at_yasu's blog

ロード的なことを

NSBitmapImageRepをちょっと拡張

NSBitmapImageRepをちょっと拡張したもの。

現在、NSBitmapImageRepでは、bitmapDataメソッドで画像のピクセルデータが取得できますが、RGB, CMYKかは利用者が判断しなければなりません。

ので、getRGB(), getCMYK()というメソッドをカテゴリクラスとして実装して取得する、と言うものを書きました。


ちなみに、RGBからCMYKの変換は色が薄くなり、CMYKからRGBの変換がまだバグ持ちと云う者ですが・・・


使用例はこちら。

第一引数にbitmapファイルをしていすると、bitmapファイルをCMYKに変換してそれをHex表記し、第二引数のファイルに書き出すコマンドラインプログラム。
ちなみに書き出したファイルのサイズは、元ファイルの3倍になります。

#include <CoreFoundation/CoreFoundation.h>
#include "myBitmapImageRep.h"

int main (int argc, const char * argv[]) {
    NSString *bitmapPath, *outputPath;
    
    if (argc <= 2) {
        fprintf(stderr, "%s [bitmap file] [output file]", argv[0]);
        exit(1);
    }
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
    bitmapPath = [NSString stringWithUTF8String:argv[1]];
    outputPath = [NSString stringWithUTF8String:argv[2]];
    
    NSBitmapImageRep *rep = [NSBitmapImageRep imageRepWithContentsOfFile:bitmapPath];
    NSString *cmyk = [[rep getCMYK] description];

    NSError *err = [NSError errorWithDomain:@"RGBCMYK_BitmapImageRep.a-yasui.info" code:0 userInfo:nil];
    if ([cmyk writeToFile:outputPath atomically:YES encoding:NSASCIIStringEncoding error:&err]) {
        fprintf(stdout,"write out to %s", argv[2]);
    }
    else
    {
        fprintf(stderr,"write error. sorry.");
    }
    
    [pool release];
    exit(0);
}

ソース

@interface NSBitmapImageRep (NSBitmapImageRep)
- (NSData *) getRGB;
- (NSData *) getRGBA;
- (NSData *) getCMYK;
- (NSData *) getCMYKA;
@end
@implementation NSBitmapImageRep (NSBitmapImageRep)
#define _min(x,y) ((x)>(y))?(y):(x)
#define _max(x,y) ((x)>(y))?(x):(y)

#define _C cmyk[0]
#define _M cmyk[1]
#define _Y cmyk[2]
#define _K cmyk[3]
#define _CMYKA cmyk[4]

#define _R  rgb[0]
#define _G  rgb[1]
#define _B  rgb[2]
#define _RGBA rgb[3]

- (NSData *) getRGB
{
    // ex, http://image-d.isp.jp/commentary/color_cformula/CMYK.html
    // RGB => CMYK (any range (0..1.0)
    //
    // k = _min(1-R, 1-G, 1-B)
    // C = (1 - R - K)/(1-K)
    // M = (1 - G - K)/(1-K)
    // Y = (1 - B - K)/(1-K)
    
    NSMutableData *data = nil;
    
    if (([[self colorSpaceName] isEqualToString:NSCalibratedRGBColorSpace]) ||
        ([[self colorSpaceName] isEqualToString:NSDeviceRGBColorSpace]))
    {
        // RGB
        NSLog(@"getRGB : RGB");
        unsigned long size = [self pixelsWide] * [self pixelsHigh];
        unsigned int spp = [self samplesPerPixel];
        unsigned int noAlphaSpp = ([self hasAlpha])?spp-1:spp;
        unsigned long imageSize = size * noAlphaSpp;
        unsigned char *imageBytes = [self bitmapData];
        unsigned long i = 0, j = 0;
        
        // swap
        NSLog(@"getRGB : imageSize => %ld", imageSize);
        unsigned char *buff = (unsigned char*)malloc((imageSize+1)*sizeof(unsigned char));
        if (buff == NULL) {
            NSLog(@"getRGB Malloc Error");
            return nil;
        }
        
        if (spp == noAlphaSpp) {
            memcpy(buff, imageBytes,imageSize);
        } else {
            for (i = 0, j = 0; i < size*spp; i+=spp, j+=noAlphaSpp) {
                buff[j] = imageBytes[i];
                buff[j+1] = imageBytes[i+1];
                buff[j+2] = imageBytes[i+2];
            }
        }
        
        data = [NSData dataWithBytes:buff length:imageSize];
        free(buff);
    }
    else if ([[self colorSpaceName] isEqualToString:NSDeviceCMYKColorSpace])
    {
        // CMYK => RGB
        NSLog(@"getRGB : CMYK -> RGB");
        unsigned int spp = [self samplesPerPixel];
        unsigned long size = [self pixelsWide] * [self pixelsHigh];
        unsigned long i = 0;
        unsigned char *imageBytes = [self bitmapData];
        char *buff = NULL;
        
        data = [NSMutableData dataWithCapacity:size*3];
        
        buff = (char*)malloc(size*3*sizeof(char));
        if (buff == NULL) {
            NSLog(@"Malloc error");
            return data;
        }
        
        for (i = 0; i < size*spp; i+=spp) {
            unsigned char *char_cmyk = (imageBytes + i);
            unsigned char rgb[4];
            unsigned char cmyk[5] = {
                char_cmyk[0],
                char_cmyk[1],
                char_cmyk[2],
                char_cmyk[3],
                char_cmyk[4]
            };
            
            _R = 255 - _min(255, ((255 - _K)*_C + 255*_K)/255);
            _G = 255 - _min(255, ((255 - _K)*_M + 255*_K)/255);
            _B = 255 - _min(255, ((255 - _K)*_Y + 255*_K)/255);
            _RGBA = _CMYKA;

            [data appendBytes:rgb length:3];
        }
        
        free(buff);
    }
    else {
        // cannot
    }
    
    return data;
}

- (NSData *) getRGBA
{
    // ex, http://image-d.isp.jp/commentary/color_cformula/CMYK.html
    // RGB => CMYK (any range (0..1.0)
    //
    // k = _min(1-R, 1-G, 1-B)
    // C = (1 - R - K)/(1-K)
    // M = (1 - G - K)/(1-K)
    // Y = (1 - B - K)/(1-K)
    
    NSMutableData *data = nil;
    
    if (([[self colorSpaceName] isEqualToString:NSCalibratedRGBColorSpace]) ||
        ([[self colorSpaceName] isEqualToString:NSDeviceRGBColorSpace]))
    {
        // RGB
        NSLog(@"getRGB : RGB");
        unsigned long size = [self pixelsWide] * [self pixelsHigh];
        unsigned int spp = [self samplesPerPixel];
        unsigned int hasAlphaSpp = ([self hasAlpha])?spp:spp+1;
        unsigned long imageSize = size * hasAlphaSpp;
        unsigned char *imageBytes = [self bitmapData];
        unsigned long i = 0, j = 0;
        BOOL hasAlpha = [self hasAlpha];
        
        
        // swap
        unsigned char *buff = (unsigned char*)malloc((imageSize+1)*sizeof(unsigned char));
        if (buff == NULL) {
            NSLog(@"getRGB Malloc Error");
            return nil;
        }
        
        for (i = 0, j = 0; i < size*spp; i+=spp, j+=hasAlphaSpp) {
            buff[j] = imageBytes[i];
            buff[j+1] = imageBytes[i+1];
            buff[j+2] = imageBytes[i+2];
            buff[j+3] = (hasAlpha)?imageBytes[i+3]:1.0;
        }
        
        data = [NSData dataWithBytes:buff length:imageSize];
        free(buff);
    }
    else if ([[self colorSpaceName] isEqualToString:NSDeviceCMYKColorSpace])
    {
        // CMYK => RGB
        NSLog(@"getRGB : CMYK -> RGB");
        unsigned int spp = [self samplesPerPixel];
        unsigned long size = [self pixelsWide] * [self pixelsHigh];
        unsigned long i = 0;
        unsigned char *imageBytes = [self bitmapData];
        char *buff = NULL;
        
        data = [NSMutableData dataWithCapacity:size*3];
        
        buff = (char*)malloc(size*3*sizeof(char));
        if (buff == NULL) {
            NSLog(@"Malloc error");
            return data;
        }
        
        for (i = 0; i < size*spp; i+=spp) {
            unsigned char char_rgb[3] = "\0";
            unsigned char *char_cmyk = (imageBytes + i);
            unsigned char rgb[4];
            unsigned char cmyk[5] = {
                char_cmyk[0],
                char_cmyk[1],
                char_cmyk[2],
                char_cmyk[3],
                char_cmyk[4]
            };
            
            _R = 255 - _min(255, ((255 - _K)*_C + 255*_K)/255);
            _G = 255 - _min(255, ((255 - _K)*_M + 255*_K)/255);
            _B = 255 - _min(255, ((255 - _K)*_Y + 255*_K)/255);
            _RGBA = _CMYKA;
            
            [data appendBytes:char_rgb length:4];
        }
        
        free(buff);
    }
    else {
        // cannot
    }
    return data;
}

- (NSData *) getCMYK
{
    // ex, http://image-d.isp.jp/commentary/color_cformula/CMYK.html
    // CMYK => RGB (any range (0..1.0))
    //
    // R = 1 - _min(1, C*(1-K)+k)
    // G = 1 - _min(1, M*(1-K)+k)
    // B = 1 - _min(1, Y*(1-K)+k)
    
    NSMutableData *data = nil;

    if (([[self colorSpaceName] isEqualToString:NSCalibratedRGBColorSpace]) ||
        ([[self colorSpaceName] isEqualToString:NSDeviceRGBColorSpace]))
    {
        // RGB => CMYK
        NSLog(@"getRGB : RGB => CMYK");
        unsigned int spp = [self samplesPerPixel];
        unsigned long size = [self pixelsWide] * [self pixelsHigh];
        unsigned long i = 0;
        unsigned char *imageBytes = [self bitmapData];
        
        data = [NSMutableData dataWithCapacity:size*4];
        
        unsigned char * buff = (unsigned char*)malloc(size*4*sizeof(unsigned char));
        if (buff == NULL) {
            NSLog(@"Malloc error");
            return data;
        }
        
        for (i = 0; i < size*spp; i+=spp) {
            unsigned char *char_rgb = (imageBytes + i);
            unsigned char rgb[3] = {
                255 - char_rgb[0],
                255 - char_rgb[1],
                255 - char_rgb[2]
            };
            unsigned char cmyk[4];
            
            _K = _min(_R, _min(_G, _B));
            
            if (_K == 255) {
                _C = 0;
                _M = 0;
                _Y = 0;
            } else {
                _C = (_R - _K)*255/(255 - _K);
                _M = (_G - _K)*255/(255 - _K);
                _Y = (_B - _K)*255/(255 - _K);
            }
            
            [data appendBytes:cmyk length:4];
        }
        
        free(buff);
    }
    else if ([[self colorSpaceName] isEqualToString:NSDeviceCMYKColorSpace])
    {
        //  CMYK
        NSLog(@"getRGB :  CMYK");
        unsigned long size = [self pixelsWide] * [self pixelsHigh];
        unsigned int spp = [self samplesPerPixel];
        unsigned int noAlphaSpp = ([self hasAlpha])?spp-1:spp;
        unsigned long imageSize = size * noAlphaSpp;
        unsigned char *imageBytes = [self bitmapData];
        unsigned long i = 0, j = 0;
        
        // swap
        unsigned char* buff = (unsigned char*)malloc((imageSize+1)*sizeof(unsigned char));
        if (buff == NULL) {
            NSLog(@"getRGB Malloc Error");
            return nil;
        }
        
        for (i = 0, j = 0; i < size*spp; i+=spp, j+=noAlphaSpp) {
            buff[j] = imageBytes[i];
            buff[j+1] = imageBytes[i+1];
            buff[j+2] = imageBytes[i+2];
            buff[j+3] = imageBytes[i+3];
        }
        
        data = [NSData dataWithBytes:buff length:imageSize];
        free(buff);
    }
    else {
        // cannot
    }
    
    return data;
}

- (NSData *) getCMYKA
{
    // ex, http://image-d.isp.jp/commentary/color_cformula/CMYK.html
    // CMYK => RGB (any range (0..1.0))
    //
    // R = 1 - _min(1, C*(1-K)+k)
    // G = 1 - _min(1, M*(1-K)+k)
    // B = 1 - _min(1, Y*(1-K)+k)
    
    NSMutableData *data = nil;
    
    if (([[self colorSpaceName] isEqualToString:NSCalibratedRGBColorSpace]) ||
        ([[self colorSpaceName] isEqualToString:NSDeviceRGBColorSpace]))
    {
        // RGB => CMYK
        NSLog(@"getRGB : RGB => CMYK");
        unsigned int spp = [self samplesPerPixel];
        unsigned long size = [self pixelsWide] * [self pixelsHigh];
        unsigned long i = 0;
        unsigned char *imageBytes = [self bitmapData];
        BOOL alpha = [self hasAlpha];
        
        data = [NSMutableData dataWithCapacity:size*4];
        
        unsigned char * buff = (unsigned char*)malloc(size*4*sizeof(unsigned char));
        if (buff == NULL) {
            NSLog(@"Malloc error");
            return data;
        }
        
        for (i = 0; i < size*spp; i+=spp) {
            unsigned char *char_rgb = (imageBytes + i);
            unsigned char rgb[3] = {
                255 - char_rgb[0],
                255 - char_rgb[1],
                255 - char_rgb[2]
            };
            unsigned char cmyk[4];
            
            _K = _min(_R, _min(_G, _B));
            
            if (_K == 255) {
                _C = 0;
                _M = 0;
                _Y = 0;
            } else {
                _C = (_R - _K)*255/(255 - _K);
                _M = (_G - _K)*255/(255 - _K);
                _Y = (_B - _K)*255/(255 - _K);
            }
            _CMYKA = (alpha) ? _RGBA : 1.0;
            [data appendBytes:cmyk length:4];
        }
        
        free(buff);
    }
    else if ([[self colorSpaceName] isEqualToString:NSDeviceCMYKColorSpace])
    {
        //  CMYK
        NSLog(@"getRGB : CMYK");
        unsigned long size = [self pixelsWide] * [self pixelsHigh];
        unsigned int spp = [self samplesPerPixel];
        unsigned int hasAlphaSpp = ([self hasAlpha])?spp:spp+1;
        unsigned long imageSize = size * hasAlphaSpp;
        unsigned char *imageBytes = [self bitmapData];
        unsigned long i = 0, j = 0;
        BOOL hasAlpha = [self hasAlpha];
        
        // swap
        unsigned char *buff = (unsigned char*)malloc((imageSize+1)*sizeof(unsigned char));
        if (buff == NULL) {
            NSLog(@"getCMYKA Malloc Error");
            return nil;
        }
        
        for (i = 0, j = 0; i < size*spp; i+=spp, j+=hasAlphaSpp) {
            buff[j] = imageBytes[i];
            buff[j+1] = imageBytes[i+1];
            buff[j+2] = imageBytes[i+2];
            buff[j+3] = imageBytes[i+3];
            buff[j+4] = (hasAlpha)?imageBytes[i+4]:1.0;
        }
        
        data = [NSData dataWithBytes:buff length:imageSize];
        free(buff);
    }
    else {
        // cannot
    }
    
    return data;
}

@end


ちなみに、getCYMKAは不要な物だよねぇ。勢い?で作ってしまったんだよね・・・

後、この長いのをどうにかしたいなぁ・・・