 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Frans Vander Meiren Guest
|
Posted: Mon Jan 12, 2004 10:18 am Post subject: RGB to CMYK conversion |
|
|
Hi
Anyone who can explain me to convert a 24-bit RGB bitmap (DIB-format) to a
32-bit CMYK bitmap by using an ICM colorprofile?
Thanks
Frans Vander Meiren
|
|
| Back to top |
|
 |
Damon Chandler (TeamB) Guest
|
Posted: Fri Jan 16, 2004 8:39 am Post subject: Re: RGB to CMYK conversion |
|
|
Hi Frans,
The TranslateBitmapBits() function should do this for you if you use a
CMYK profile as the "destination" profile. Here's a rough example that
creates a 32-bpp CMYK bitmap from a 24-bpp sRGB bitmap...
#include <icm.h>
#pragma link "mscms.lib"
Graphics::TBitmap* sRGB2CMYKBitmap(
Graphics::TBitmap& SrcBitmap,
AnsiString cmyk_profilename
)
{
// copy the file-name of the target (CMYK) profile
TCHAR tgt_profilename[MAX_PATH];
lstrcpyn(tgt_profilename,
cmyk_profilename.c_str(), MAX_PATH);
// initialize a PROFILE structure
PROFILE tgt_profile;
tgt_profile.dwType = PROFILE_FILENAME;
tgt_profile.pProfileData = static_cast<void*>(tgt_profilename);
tgt_profile.cbDataSize =
(lstrlen(tgt_profilename) + 1) * sizeof(TCHAR);
// create the color profile object
HPROFILE const hTgtProfile = OpenColorProfile(
&tgt_profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING
);
if (hTgtProfile == NULL)
{
throw EWin32Error("OpenColorProfile() failed.");
}
// force the source bitmap to 24 bpp
SrcBitmap.PixelFormat = pf24bit;
// create the target bitmap object
std::auto_ptr<Graphics::TBitmap>
TgtBitmap(new Graphics::TBitmap());
TgtBitmap->PixelFormat = pf32bit;
TgtBitmap->Width = SrcBitmap.Width;
TgtBitmap->Height = SrcBitmap.Height;
//
// perform the color conversion...
//
try
{
// validate the profile's contents
BOOL is_valid = FALSE;
IsColorProfileValid(hTgtProfile, &is_valid);
if (!is_valid)
{
throw EWin32Error("bad profile");
}
// initialize a LOGCOLORSPACE struct
LOGCOLORSPACE lcs = {
LCS_SIGNATURE, 0x400, sizeof(LOGCOLORSPACE)
};
// sRGB color space
lcs.lcsCSType = LCS_sRGB;
// perceptual rendering intent
lcs.lcsIntent = LCS_GM_IMAGES;
// create a color transform object
HTRANSFORM const hColorTransform = CreateColorTransform(
&lcs, hTgtProfile, NULL, NORMAL_MODE + ENABLE_GAMUT_CHECKING
);
if (hColorTransform == NULL)
{
throw EWin32Error("CreateColorTransform() failed.");
}
try
{
// grab a pointer to the pixels
BITMAP src_bmp, tgt_bmp;
GetObject(SrcBitmap.Handle, sizeof(BITMAP), &src_bmp);
GetObject(TgtBitmap->Handle, sizeof(BITMAP), &tgt_bmp);
// color-match the bitmap's pixels
const bool match_ok =
TranslateBitmapBits(
hColorTransform,
src_bmp.bmBits, BM_RGBTRIPLETS,
src_bmp.bmWidth, src_bmp.bmHeight, 0,
tgt_bmp.bmBits, BM_CMYKQUADS, 0,
NULL, 0
);
if (!match_ok)
{
throw EWin32Error("TranslateBitmapBits() failed.");
}
}
__finally
{
// destroy the color transform object
DeleteColorTransform(hColorTransform);
}
}
__finally
{
// destroy the color profile object
CloseColorProfile(hTgtProfile);
}
// caller assumes ownership
return TgtBitmap.release();
}
The cmyk_profilename parameter must indicate the fully-qualified
file-name of a valid CMYK profile (you can get some here
[url]http://www.adobe.com/support/downloads/detail.jsp?ftpID=2348)[/url].
After the conversion, you can access the C, M, Y, and K values from the
returned CMYK bitmap by casting each scanline to a COLORREF and then
using the GetCValue(), GetMValue(), GetYValue(), and GetKValue()
macros. For example...
inline BYTE clip(int x)
{
if (x > 255) return 255;
if (x < 0) return 0;
return x;
}
void __fastcall TForm1::
ColorMatchButtonClick(TObject *Sender)
{
std::auto_ptr
sRGB2CMYKBitmap(
*Image1->Picture->Bitmap, "c:\USWebUncoated.icc"
)
);
// convert back to uncalibrated RGB as a sanity check
int const cx = CMYKBitmap->Width;
int const cy = CMYKBitmap->Height;
for (int y0 = 0; y0 < cy; ++y0)
{
RGBQUAD* const pRGBRow = static_cast
CMYKBitmap->ScanLine[y0]
);
COLORREF const* const pColorRow = static_cast<COLORREF*>(
CMYKBitmap->ScanLine[y0]
);
for (int x0 = 0; x0 < cx; ++x0)
{
int const c = GetCValue(pColorRow[x0]);
int const m = GetMValue(pColorRow[x0]);
int const y = GetYValue(pColorRow[x0]);
int const k = GetKValue(pColorRow[x0]);
pRGBRow[x0].rgbRed = clip(255 - (c + k));
pRGBRow[x0].rgbGreen = clip(255 - (m + k));
pRGBRow[x0].rgbBlue = clip(255 - (y + k));
}
}
// display the bitmap
Image2->Picture->Assign(CMYKBitmap.get());
}
HTH,
Damon (TeamB)
|
|
| Back to top |
|
 |
Frans Vander Meiren Guest
|
Posted: Wed Jan 28, 2004 6:55 pm Post subject: Re: RGB to CMYK conversion |
|
|
Thanks Deamon
Greetings, Frans Vander Meiren
"Damon Chandler (TeamB)" <dmc27 (AT) cornell (DOT) edu> schreef in bericht
news:4007A334.69D35C77 (AT) cornell (DOT) edu...
| Quote: | Hi Frans,
The TranslateBitmapBits() function should do this for you if you use a
CMYK profile as the "destination" profile. Here's a rough example that
creates a 32-bpp CMYK bitmap from a 24-bpp sRGB bitmap...
#include <icm.h
#pragma link "mscms.lib"
Graphics::TBitmap* sRGB2CMYKBitmap(
Graphics::TBitmap& SrcBitmap,
AnsiString cmyk_profilename
)
{
// copy the file-name of the target (CMYK) profile
TCHAR tgt_profilename[MAX_PATH];
lstrcpyn(tgt_profilename,
cmyk_profilename.c_str(), MAX_PATH);
// initialize a PROFILE structure
PROFILE tgt_profile;
tgt_profile.dwType = PROFILE_FILENAME;
tgt_profile.pProfileData = static_cast
tgt_profile.cbDataSize =
(lstrlen(tgt_profilename) + 1) * sizeof(TCHAR);
// create the color profile object
HPROFILE const hTgtProfile = OpenColorProfile(
&tgt_profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING
);
if (hTgtProfile == NULL)
{
throw EWin32Error("OpenColorProfile() failed.");
}
// force the source bitmap to 24 bpp
SrcBitmap.PixelFormat = pf24bit;
// create the target bitmap object
std::auto_ptr<Graphics::TBitmap
TgtBitmap(new Graphics::TBitmap());
TgtBitmap->PixelFormat = pf32bit;
TgtBitmap->Width = SrcBitmap.Width;
TgtBitmap->Height = SrcBitmap.Height;
//
// perform the color conversion...
//
try
{
// validate the profile's contents
BOOL is_valid = FALSE;
IsColorProfileValid(hTgtProfile, &is_valid);
if (!is_valid)
{
throw EWin32Error("bad profile");
}
// initialize a LOGCOLORSPACE struct
LOGCOLORSPACE lcs = {
LCS_SIGNATURE, 0x400, sizeof(LOGCOLORSPACE)
};
// sRGB color space
lcs.lcsCSType = LCS_sRGB;
// perceptual rendering intent
lcs.lcsIntent = LCS_GM_IMAGES;
// create a color transform object
HTRANSFORM const hColorTransform = CreateColorTransform(
&lcs, hTgtProfile, NULL, NORMAL_MODE + ENABLE_GAMUT_CHECKING
);
if (hColorTransform == NULL)
{
throw EWin32Error("CreateColorTransform() failed.");
}
try
{
// grab a pointer to the pixels
BITMAP src_bmp, tgt_bmp;
GetObject(SrcBitmap.Handle, sizeof(BITMAP), &src_bmp);
GetObject(TgtBitmap->Handle, sizeof(BITMAP), &tgt_bmp);
// color-match the bitmap's pixels
const bool match_ok =
TranslateBitmapBits(
hColorTransform,
src_bmp.bmBits, BM_RGBTRIPLETS,
src_bmp.bmWidth, src_bmp.bmHeight, 0,
tgt_bmp.bmBits, BM_CMYKQUADS, 0,
NULL, 0
);
if (!match_ok)
{
throw EWin32Error("TranslateBitmapBits() failed.");
}
}
__finally
{
// destroy the color transform object
DeleteColorTransform(hColorTransform);
}
}
__finally
{
// destroy the color profile object
CloseColorProfile(hTgtProfile);
}
// caller assumes ownership
return TgtBitmap.release();
}
The cmyk_profilename parameter must indicate the fully-qualified
file-name of a valid CMYK profile (you can get some here
[url]http://www.adobe.com/support/downloads/detail.jsp?ftpID=2348)[/url].
After the conversion, you can access the C, M, Y, and K values from the
returned CMYK bitmap by casting each scanline to a COLORREF and then
using the GetCValue(), GetMValue(), GetYValue(), and GetKValue()
macros. For example...
inline BYTE clip(int x)
{
if (x > 255) return 255;
if (x < 0) return 0;
return x;
}
void __fastcall TForm1::
ColorMatchButtonClick(TObject *Sender)
{
std::auto_ptr
sRGB2CMYKBitmap(
*Image1->Picture->Bitmap, "c:\USWebUncoated.icc"
)
);
// convert back to uncalibrated RGB as a sanity check
int const cx = CMYKBitmap->Width;
int const cy = CMYKBitmap->Height;
for (int y0 = 0; y0 < cy; ++y0)
{
RGBQUAD* const pRGBRow = static_cast
CMYKBitmap->ScanLine[y0]
);
COLORREF const* const pColorRow = static_cast<COLORREF*>(
CMYKBitmap->ScanLine[y0]
);
for (int x0 = 0; x0 < cx; ++x0)
{
int const c = GetCValue(pColorRow[x0]);
int const m = GetMValue(pColorRow[x0]);
int const y = GetYValue(pColorRow[x0]);
int const k = GetKValue(pColorRow[x0]);
pRGBRow[x0].rgbRed = clip(255 - (c + k));
pRGBRow[x0].rgbGreen = clip(255 - (m + k));
pRGBRow[x0].rgbBlue = clip(255 - (y + k));
}
}
// display the bitmap
Image2->Picture->Assign(CMYKBitmap.get());
}
HTH,
Damon (TeamB)
|
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|