CMYK convert RGB

libjpeg 处理CMYK 格式数据以及iCC配置文件

  • ICC文件,又叫ICC Color Profile,是指设备管理色彩特性的文件,各种具有色彩管理功能的软件(如photoshop)可以依据ICC文件的配置对不同设备的颜色特点进行准确地显示,转换和改变。同时,也能让颜色在不同设备上的传递过程时的失真最小 。
  • ICC文件是将所有和设备有关的颜色数据(RGB和CMYK数据),一一对应到和设备无关的Lab颜色模式上。从而通过Lab模式做为传递中介,保持所有颜色外观的一致,icc文件用来描述设备的颜色特性,并用于后期的空间转换。如显示器的icc文件,记录了显示器RGB和XYZ颜色关系,打印机和印刷机的icc记录了CMYK和lab颜色关系,XYZ,lab等颜色空间是与设备无关的颜色空间,统称为PCS空间,为颜色转换提供了中间空间。可以想象,如果显示器模拟印刷机的颜色,不可能将印刷机CMYK直接转换成显示器RGB,因为CMYK是设备的输出值,RGB是显示器的输入值,那怎么产生联系?CMYK-LAB-XYZ-RGB,这样就能进行颜色的转换
  • ICC profile 的配置文件表:https://www.kamilet.cn/icc-profile/

CMYK convert RGB

  • 对于存储格式为CMYK的图像,通常应用于jpeg和tiff格式中,利用libjpeg和libtiff库解析图片数据时,需要根据解析的方式进行相应的转换

  • 解析libjpeg时

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include "libjpeg/jpeglib.h"
    #include "libjpeg/jerror.h"
    
    typedef struct _Mat{
    	unsigned int nImageWidth;
    	unsigned int nImageHeight;
    	unsigned int nChannels;
    	unsigned char* pImageData; // 像素数据,RGB排列
    } Mat, *pHddMat;
    
    int decodeJpgImage(const char* jpgSource, Mat* pImgMat){
    	struct jpeg_decompress_struct cinfo;
    	jpeg_error_manager jerr;
    	FILE* fp;
    
    	JSAMPARRAY buffer;
    	int row_stride = 0;
    	unsigned char* dst = NULL;
    	int rgb_size;
    
    	fp = fopen(jpgSource, "rb");
    	if (fp == NULL)
    	{
    		printf("open input jpg file %s failed.\n", jpgSource);
    		return -1;
    	}
    	cinfo.err = jpeg_std_error(&jerr.pub);
    	jerr.pub.error_exit = jpeg_error_exit;
    
    	if (setjmp(jerr.setjmp_buffer))
    	{
    		jpeg_destroy_decompress(&cinfo);
    		fclose(fp);
    		printf("parse %s  input jpg file failed.\n", jpgSource);
    		return -2;
    	}
    
    	jpeg_create_decompress(&cinfo);
    
    	// step 2a: specify data source (eg, a handle)
    	jpeg_stdio_src(&cinfo, fp);
    	// step 2b: save special markers for later reading
    
    	jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF);
    	int m = 0;
    	for (m = 0; m < 16; m++) {
    		jpeg_save_markers(&cinfo, JPEG_APP0 + m, 0xFFFF);
    	}
    
    	// step 3: read handle parameters with jpeg_read_header()
    	int retcode = jpeg_read_header(&cinfo, TRUE);
    	
    	int colorType = cinfo.num_components;
    	switch (colorType) {
    	case 1:
    		cinfo.out_color_space = JCS_GRAYSCALE;
    		cinfo.out_color_components = 1;
    		break;
    	case 4:
    		cinfo.out_color_space = JCS_CMYK;
    		cinfo.out_color_components = 4;
    		break;
    	default:
    		cinfo.out_color_space = JCS_RGB;
    		cinfo.out_color_components = 3;
    		break;
    	}
    	jpeg_start_decompress(&cinfo);
    
    	row_stride = cinfo.output_width * cinfo.output_components;
    	rgb_size = row_stride * cinfo.output_height; // image data size
    
    	buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
    
    	pImgMat->nImageWidth = cinfo.output_width;
    	pImgMat->nImageHeight = cinfo.output_height;
    	pImgMat->nChannels = cinfo.num_components;
    	pImgMat->pImageData = (unsigned char*)malloc(sizeof(unsigned char) * rgb_size); // 分配总内存
    
    	dst = pImgMat->pImageData;
    	while (cinfo.output_scanline < cinfo.output_height){
            JSAMPROW src = buffer[0];
    		jpeg_read_scanlines(&cinfo, buffer, 1);   // 解压每一行
    		// if input is CMYK 
            for(unsigned x = 0; x < cinfo.output_width; x++) {
                // CMYK pixels are inverted
                dst[0] = ~src[0];	// C
                dst[1] = ~src[1];	// M
                dst[2] = ~src[2];	// Y
                dst[3] = ~src[3];	// K
                src += 4;
                dst += 4;
            }
            //memcpy(dst, buffer[0], row_stride);
    		//dst += row_stride;
    	}
    
    	jpeg_finish_decompress(&cinfo);
    	jpeg_destroy_decompress(&cinfo);
    	
    	fclose(fp);
    	
    	return 0;
    }
    
    
    int encodeJpgImage(const char* jpgSavefile, Mat* jpgImg,int quality){
    	struct jpeg_compress_struct cinfo;
    	struct jpeg_error_mgr jerr;
    	int row_stride = 0;
    	FILE* fp = NULL;
    	JSAMPROW row_pointer[1];
    
    	cinfo.err = jpeg_std_error(&jerr);
    
    	jpeg_create_compress(&cinfo);
    	fp = fopen(jpgSavefile, "wb");
    	if (fp == NULL)
    	{
    		printf("open output %s  file failed.\n", jpgSavefile);
    		return -1;
    	}
    
    	jpeg_stdio_dest(&cinfo, fp);
    	cinfo.image_width = jpgImg->nImageWidth;
    	cinfo.image_height = jpgImg->nImageHeight;
    	cinfo.input_components = jpgImg->nChannels;
    
    	int colorType = cinfo.input_components;
    	switch (colorType) {
    	case 1:
    		cinfo.in_color_space = JCS_GRAYSCALE;
    		break;
    	case 4:
    		cinfo.in_color_space = JCS_CMYK;
    		break;
    	default:
    		cinfo.in_color_space = JCS_RGB;
    		break;
    	}
    
    	jpeg_set_defaults(&cinfo);
    	jpeg_set_quality(&cinfo, quality, TRUE);
    	//cinfo.optimize_coding = TRUE;
    	jpeg_start_compress(&cinfo, TRUE);
    
    	row_stride = jpgImg->nImageWidth * cinfo.input_components;
    
    	while (cinfo.next_scanline < cinfo.image_height){
    		row_pointer[0] = &jpgImg->pImageData[cinfo.next_scanline * row_stride];
            BYTE *target_p = row_pointer[0];
            for(unsigned x = 0; x < cinfo.image_width; x++) {
              // CMYK pixels are inverted
                target_p[0] = ~target_p[0];	// C
                target_p[1] = ~target_p[1];	// M
                target_p[2] = ~target_p[2];	// Y
                target_p[3] = ~target_p[3];	// K
    
                target_p += 4;
            }        
    		jpeg_write_scanlines(&cinfo, row_pointer, 1);
    	}
    
    	jpeg_finish_compress(&cinfo);
    	jpeg_destroy_compress(&cinfo);
    	fclose(fp);
    
    	return 0;
    }
    
    • CMYK转换RGB
     	int cols = pImgMat->nImageWidth;
     	int rows = pImgMat->nImageHeight;
     	int channels = pImgMat->nChannels;
     
     	for (int row = 0; row < rows; row++) {
     		unsigned char* imgPtr = pImgMat->pImageData + row * cols * channels;
     		for (int j = 0; j < cols; j++) {
                 int c = imgPtr[j*channels+0];
                 int m = imgPtr[j*channels+1];
                 int y = imgPtr[j*channels+2];
                 int k = imgPtr[j*channels+3];
                 
                 unsigned r = (255 - c) * (255 - k) >> 8;
                 unsigned g = (255 - m) * (255 - k) >> 8;
                 unsigned b = (255 - y) * (255 - k) >> 8;
     
                 //if read value not ~255 ops, similar to opencv library 
                 //unsigned r = k - ((255 - c)*k >> 8);
                 //unsigned g = k - ((255 - m)*k >> 8);
                 //unsigned b = k - ((255 - y)*k >> 8);
             }
         }
    

RGB to CMYK conversion formula

The R,G,B values are divided by 255 to change the range from 0…255 to 0…1:

R’ = R/255

G’ = G/255

B’ = B/255

The black key (K) color is calculated from the red (R’), green (G’) and blue (B’) colors:

K = 1-max(R’, G’, B’)

The cyan color © is calculated from the red (R’) and black (K) colors:

C = (1-R’-K) / (1-K)

The magenta color (M) is calculated from the green (G’) and black (K) colors:

M = (1-G’-K) / (1-K)

The yellow color (Y) is calculated from the blue (B’) and black (K) colors:

Y = (1-B’-K) / (1-K)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值