DEMO.DESIGN
Frequently Asked Questions
 
оглавление | demo party в ex-СССР | infused bytes e-mag | новости от ib/news | другие проекты | письмо | win koi lat

следующий фpагмент (2)
- Usenet echoes (21:200/1) -------------------------- COMP.GRAPHICS.ALGORITHMS - Msg : 111 of 112 From : vf@shadow.net 2:5030/315 24 Jan 96 21:45:06 To : All 28 Jan 96 02:46:18 Subj : Re: RGB->CMYK source code -------------------------------------------------------------------------------- X-RealName: Vinnie Falco I laughed when I saw someone ask "What is the conversion between RGB and CMYK?" AS IF! The CMYK color model, like the RGB color model, is DEVICE SPECIFIC. Read Charles Poynton's FAQ about color spaces to understand a little more. Once you understand the difference, you will realize that the Lab or XYZ color spaces are a better way to refer to colors in a device-independent fashion. To convert from CMYK to RGB, a good first step is to convert to a device-independent color space, since going from one device dependent color space to another is not simple. Lab image data is more convenient to store than XYZ data because the Lab data is easily scaled into the range 0...255, which makes it perfect for storage using unsigned char. In addition, it only exhibits a 6% variance of uniformity (I think...) If you have Lab image data, it is relatively straightforward to convert it to/from RGB using formulas where are available (see Color Space FAQ). The RGB conversion will only be accurate for the particular RGB device characterized in the conversion formula, so information about the chromaticities of the primaries (e.g. your monitor phosphors) is necessary. Plenty of info about Lab<--->RGB conversions is out there so I am not going to discuss it. What is not obvious is how to convert CMYK image data to and from device independent Lab format. The method chosen by most people which is the simplest is to literally print samples of CMYK colors onto the intended paper and sample them using a spectrophotometer. The samples can be spaced apart in about 3.125% increments covering all four axes of the CMYK color space. The spectrophotometer will give you the Lab (or XYZ) equivalent for a particular CMYK value. Keep in mind that this conversion is completely dependent on lighting conditions, inks, and paper, so if any parameters change, your conversion must be re-tabulated. Anyway, what it boils down to is two tables for converting CMYK to Lab. One table holds CMY->Lab conversions and has 33 samples per axis. The other table holds K->Lab conversions and has a full 256 samples. This gives us high accuracy where it counts (in the black), and gives us decent accuracy for the cyan, magenta, and yellow colorants. Unfortunately, you will have a lot of banding because of the granularity of the table. To get rid of this you can use tri-linear interpolation between table values. A good discussion of tri-linear interpolation can be found in Graphics Gems IV Tri-linear Interpolation My code for plugging into the lookup table and converting CMYK to Lab looks like this : The output is stored interleaved, L, a, b, L, a, b, etc... struct CMYKToLabTab { unsigned char cmy[33][33][33][3]; unsigned char k[256][3] }; void cmyktolabmap ( long rows, long cols, unsigned char *src, long srcRB, long srcCB, long srcPB, unsigned char *dest, long destRB, CMYKToLabTab *tab ) { long n1=3267, n2=3168, n3=3363, n4=3368; long x, y; srcRB-=cols*srcCB; destRB-=cols*3; for(y=rows;y;y--) { for(x=cols;x;x--) { unsigned char *s, *t, cmyk[4], ic,im,iy; long fc, fm, fy, t1, t2, t3, t4, t5, t6; long L, a, b, w1, w2, w3; s=src; cmyk[0]=*s; s+=srcPB; cmyk[1]=*s; s+=srcPB; cmyk[2]=*s; s+=srcPB; cmyk[3]=*s; src+=srcCB; ic=cmyk[0]; fc=ic&7; ic>>=3; im=cmyk[1]; fm=im&7; im>>=3; iy=cmyk[2]; fy=iy&7; iy>>=3; if (cmyk[0]==255) { ic=31; fc=8; } if (cmyk[1]==255) { im=31; fm=8; } if (cmyk[2]==255) { iy=31; fy=8; } t=&tab->cmy[ic][im][iy][0]; w1 = tab->k[cmyk[3]][0]; w2 = tab->k[cmyk[3]][1]; w3 = tab->k[cmyk[3]][2]; /* L */ t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fc * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n3; t4 = ( t1 << 3 ) + ( fc * t2 ); t5 = t3 + ( ( fm * (t4 - t3) ) >> 3 ); t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fc * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n4; t4 = ( t1 << 3 ) + ( fc * t2 ); t6 = t3 + ( ( fm * (t4 - t3) ) >> 3 ); L = ( t5 + ( ( fy * (t6 - t5) ) >> 3 ) ) >> 3; /* a */ t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fc * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n3; t4 = ( t1 << 3 ) + ( fc * t2 ); t5 = t3 + ( ( fm * (t4 - t3) ) >> 3 ); t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fc * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n4; t4 = ( t1 << 3 ) + ( fc * t2 ); t6 = t3 + ( ( fm * (t4 - t3) ) >> 3 ); a = ( t5 + ( ( fy * (t6 - t5) ) >> 3 ) ) >> 3; /* b */ t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fc * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n3; t4 = ( t1 << 3 ) + ( fc * t2 ); t5 = t3 + ( ( fm * (t4 - t3) ) >> 3 ); t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fc * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n4; t4 = ( t1 << 3 ) + ( fc * t2 ); t6 = t3 + ( ( fm * (t4 - t3) ) >> 3 ); b = ( t5 + ( ( fy * (t6 - t5) ) >> 3 ) ) >> 3; *dest++ = (L * w1) / 255; *dest++ = (((a-128L)*w1)+(128L*255L))/255L; *dest++ = (((b-128L)*w1)+(128L*255L))/255L; } src+=srcRB; dest+=destRB; } } Notice that under this scheme, a value of C, M, Y, or K of zero means 100% ink, and 255 = no ink, which seems to be the opposite of what you would expect, but it works out nicely because then between RGB, Grayscale, Lab, and CMYK, lower pixel values means darker, and higher pixel values means lighter. The passed in conversion table obeys this rule. In order to convert from Lab to CMYK, a similar table is used. Unfortunately, filling out the table is very difficult, and I don't even know how to do it. The reason it is difficult is because for each Lab value there are a multitude of possible CMYK values that will result in a perceptual match. Your choice of CMYK values will depend on Your Total Ink Limit (maximum amount of ink you can deposit in one place) Your Separation Model (Under Color Removal versus Gray Component Replacement). The process of conversion from Lab to CMYK is called separating. If anyone has a decent algorithm for doing this, let me know please. I do know that one technique involves searching the CMYK->Lab table for matches based on some criteria. If you somehow generate the table, you would use a function like this to use it : struct LabToCMYKTab { lut[33][33][33][4]; }; void labtocmykmap ( long rows, long cols, map src, long srcRB, long srcCB, long srcPB, map dest, long destRB, LabToCMYKTab *tab ) { long n1=4356, n2=4224, n3=4484, n4=4491; long x, y; LabToCMYKTab *tab; srcRB-=cols*srcCB; destRB-=cols*4; for(y=rows;y;y--) { for(x=cols;x;x--) { unsigned char *s, *t, lab[3], cmyk[4]; s=src; lab[0]=*s; s+=srcPB; lab[1]=*s; s+=srcPB; lab[2]=*s; src+=srcCB; { unsigned char iL,ia,ib; /* floored indices into tab */ unsigned long fL, fa, fb; /* fractional parts of L,a,b indices */ long t1, t2, t3, t4, t5, t6; iL=lab[0]; fL=iL&7; iL>>=3; ia=lab[1]; fa=ia&7; ia>>=3; ib=lab[2]; fb=ib&7; ib>>=3; if (lab[0]==255) { iL = 31; fL = 8; } if (lab[1]==255) { ia = 31; fa = 8; } if (lab[2]==255) { ib = 31; fb = 8; } t=&tab->lut[iL][ia][ib][0]; // long n1=4356, n2=4224, n3=4484, n4=4491; /* C */ t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fL * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n3; t4 = ( t1 << 3 ) + ( fL * t2 ); t5 = t3 + ( ( fa * (t4 - t3) ) >> 3 ); t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fL * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n4; t4 = ( t1 << 3 ) + ( fL * t2 ); t6 = t3 + ( ( fa * (t4 - t3) ) >> 3 ); cmyk[0] = ( t5 + ( ( fb * (t6 - t5) ) >> 3 ) ) >> 3; /* M */ t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fL * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n3; t4 = ( t1 << 3 ) + ( fL * t2 ); t5 = t3 + ( ( fa * (t4 - t3) ) >> 3 ); t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fL * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n4; t4 = ( t1 << 3 ) + ( fL * t2 ); t6 = t3 + ( ( fa * (t4 - t3) ) >> 3 ); cmyk[1] = ( t5 + ( ( fb * (t6 - t5) ) >> 3 ) ) >> 3; /* Y */ t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fL * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n3; t4 = ( t1 << 3 ) + ( fL * t2 ); t5 = t3 + ( ( fa * (t4 - t3) ) >> 3 ); t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fL * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n4; t4 = ( t1 << 3 ) + ( fL * t2 ); t6 = t3 + ( ( fa * (t4 - t3) ) >> 3 ); cmyk[2] = ( t5 + ( ( fb * (t6 - t5) ) >> 3 ) ) >> 3; /* K */ t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fL * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n3; t4 = ( t1 << 3 ) + ( fL * t2 ); t5 = t3 + ( ( fa * (t4 - t3) ) >> 3 ); t1 =*t; t+=n1; t2=*t - t1; t-=n2; t3 = ( t1 << 3 ) + ( fL * t2 ); t1 =*t; t+=n1; t2=*t - t1; t-=n4; t4 = ( t1 << 3 ) + ( fL * t2 ); t6 = t3 + ( ( fa * (t4 - t3) ) >> 3 ); cmyk[3] = ( t5 + ( ( fb * (t6 - t5) ) >> 3 ) ) >> 3; *dest++ = cmyk[0]; *dest++ = cmyk[1]; *dest++ = cmyk[2]; *dest++ = cmyk[3]; } } src+=srcRB; dest+=destRB; } } There may be a few slight problems with these algorithms, esp. because the last table entry corresponds to 255 instead of 256, which can cause the divide/mod stuff at the top to be up to 1/8 off the correct value. Adobe Photoshop (TM) creates separation setup and printing inks tables which have EXACTLY the same format as these tables described here. Hope this helps.

Всего 1 фpагмент(а/ов) |пpедыдущий фpагмент (1)

Если вы хотите дополнить FAQ - пожалуйста пишите.

design/collection/some content by Frog,
DEMO DESIGN FAQ (C) Realm Of Illusion 1994-2000,
При перепечатке материалов этой страницы пожалуйста ссылайтесь на источник: "DEMO.DESIGN FAQ, http://www.enlight.ru/demo/faq".