我正在使用PIL处理上传的图片。不幸的是,我在从CMYK到RGB的颜色转换方面遇到了麻烦,因为产生的图像色调和对比度发生了变化。
我怀疑它只进行直接数字转换。 PIL或其上构建的任何东西是否具有Adobian虚拟证明使用嵌入式配置文件,转换为目标,保留数字我可用于转换的工具?
在我所有健康的无知和缺乏经验中,这种对我的冲击,让我陷入困境。我真的很想完成这项工作,而不会在这一点上对任何复杂的色彩空间,变换和必要的数学进行处理。
虽然我之前从未使用过它,但如果有人有经验证明它可以以优雅的方式执行它,我也会使用ImageMagick进行此处理步骤。
答案 0 :(得分:8)
所以我花了很长时间才与其他人提到Little CMS,这是最受欢迎的色彩管理开源解决方案。我结束了窥探Python绑定,找到了旧的pyCMS
和一些关于PIL支持Little CMS的表面观念。
事实上,有人支持Little CMS,它在一个非常棒的单行中提到:
CMS支持:littleCMS(建议使用1.1.5或更高版本)。
该文档不包含任何引用,没有主题指南,Google没有抓取任何内容,他们的邮件列表已关闭......但是在源代码中挖掘出一个PIL.ImageCms
模块,该模块已有详细记录并完成工作。希望这可以使某人免受凌乱的互联网挖掘。
让自己成为一个cookie ......
答案 1 :(得分:1)
这是2019年,情况已经改变。您的问题比乍看之下要复杂得多。问题是,从CMYK到RGB以及从RGB到CMYK的过程并不简单。如果例如您在Photoshop中打开图像并在那里进行转换,此转换还有2个附加参数:源颜色配置文件和目标颜色配置文件。这些改变很大!对于典型的用例,您将假设Adobe RGB 1998
在RGB端,并说Coated FOGRA 39
在CMYK端。这两个额外的信息向转换器阐明了如何处理输入和输出上的颜色。接下来需要的是一种转换机制,为此,Little CMS确实是一个很好的工具。它是MIT许可的产品((经过相当长一段时间自己寻找解决方案之后),如果您确实需要使用python方式转换颜色的话,我建议您进行以下设置:
pip install littlecms
pip install Pillow
在littlecms的/tests
文件夹中,您会找到很多示例。我会允许自己对一种测试进行特殊的修改。在获得代码之前,请让我告诉您一些有关这些颜色配置文件的信息。在Windows上,就像我的情况一样,您会在Windows存储其颜色配置文件的文件夹.icc
中找到一组扩展名为C:\Windows\System32\spool\drivers\color
的文件。您可以从https://www.adobe.com/support/downloads/iccprofiles/iccprofiles_win.html之类的站点下载其他配置文件,然后只需双击相应的.icc
文件即可将其安装在Windows上。我提供的示例取决于此类配置文件,Little CMS使用这些配置文件来进行这些神奇的颜色转换。我是半专业的图形设计师,需要能够将某些颜色的字符从CMYK转换为RGB,反之亦然。我的设置是RGB:Adobe RGB 1998和CMYK:Coated FOGRA 39(这些设置是大多数书本打印机推荐的,我可以在此使用书本进行打印)。上面提到的颜色配置文件对我来说与Photoshop和InDesign进行的转换非常相似。不过请注意,与PS和Id为相同输入提供的颜色相比,颜色会稍微 (大约降低1%)。我试图找出原因...
小程序:
import littlecms as lc
from PIL import Image
def rgb2cmykColor(rgb, psrc='C:\\Windows\\System32\\spool\\drivers\\color\\AdobeRGB1998.icc', pdst='C:\\Windows\\System32\\spool\\drivers\\color\\CoatedFOGRA39.icc') :
ctxt = lc.cmsCreateContext(None, None)
white = lc.cmsD50_xyY() # Set white point for D50
dst_profile = lc.cmsOpenProfileFromFile(pdst, 'r')
src_profile = lc.cmsOpenProfileFromFile(psrc, 'r') # cmsCreate_sRGBProfile()
transform = lc.cmsCreateTransform(src_profile, lc.TYPE_RGB_8, dst_profile, lc.TYPE_CMYK_8,
lc.INTENT_RELATIVE_COLORIMETRIC, lc.cmsFLAGS_NOCACHE)
n_pixels = 1
in_comps = 3
out_comps = 4
rgb_in = lc.uint8Array(in_comps * n_pixels)
cmyk_out = lc.uint8Array(out_comps * n_pixels)
for i in range(in_comps):
rgb_in[i] = rgb[i]
lc.cmsDoTransform(transform, rgb_in, cmyk_out, n_pixels)
cmyk = tuple(cmyk_out[i] for i in range(out_comps * n_pixels))
return cmyk
def cmyk2rgbColor(cmyk, psrc='C:\\Windows\\System32\\spool\\drivers\\color\\CoatedFOGRA39.icc', pdst='C:\\Windows\\System32\\spool\\drivers\\color\\AdobeRGB1998.icc') :
ctxt = lc.cmsCreateContext(None, None)
white = lc.cmsD50_xyY() # Set white point for D50
dst_profile = lc.cmsOpenProfileFromFile(pdst, 'r')
src_profile = lc.cmsOpenProfileFromFile(psrc, 'r') # cmsCreate_sRGBProfile()
transform = lc.cmsCreateTransform(src_profile, lc.TYPE_CMYK_8, dst_profile, lc.TYPE_RGB_8,
lc.INTENT_RELATIVE_COLORIMETRIC, lc.cmsFLAGS_NOCACHE)
n_pixels = 1
in_comps = 4
out_comps = 3
cmyk_in = lc.uint8Array(in_comps * n_pixels)
rgb_out = lc.uint8Array(out_comps * n_pixels)
for i in range(in_comps):
cmyk_in[i] = cmyk[i]
lc.cmsDoTransform(transform, cmyk_in, rgb_out, n_pixels)
rgb = tuple(rgb_out[i] for i in range(out_comps * n_pixels))
return rgb
def rgb2cmykImage(PILImage, psrc='C:\\Windows\\System32\\spool\\drivers\\color\\AdobeRGB1998.icc', pdst='C:\\Windows\\System32\\spool\\drivers\\color\\CoatedFOGRA39.icc') :
ctxt = lc.cmsCreateContext(None, None)
white = lc.cmsD50_xyY() # Set white point for D50
dst_profile = lc.cmsOpenProfileFromFile(pdst, 'r')
src_profile = lc.cmsOpenProfileFromFile(psrc, 'r')
transform = lc.cmsCreateTransform(src_profile, lc.TYPE_RGB_8, dst_profile, lc.TYPE_CMYK_8,
lc.INTENT_RELATIVE_COLORIMETRIC, lc.cmsFLAGS_NOCACHE)
n_pixels = PILImage.size[0]
in_comps = 3
out_comps = 4
n_rows = 16
rgb_in = lc.uint8Array(in_comps * n_pixels * n_rows)
cmyk_out = lc.uint8Array(out_comps * n_pixels * n_rows)
outImage = Image.new('CMYK', PILImage.size, 'white')
in_row = Image.new('RGB', (PILImage.size[0], n_rows), 'white')
out_row = Image.new('CMYK', (PILImage.size[0], n_rows), 'white')
out_b = bytearray(n_pixels * n_rows * out_comps)
row = 0
while row < PILImage.size[1] :
in_row.paste(PILImage, (0, -row))
data_in = in_row.tobytes('raw')
j = in_comps * n_pixels * n_rows
for i in range(j):
rgb_in[i] = data_in[i]
lc.cmsDoTransform(transform, rgb_in, cmyk_out, n_pixels * n_rows)
for j in cmyk_out :
out_b[j] = cmyk_out[j]
out_row = Image.frombytes('CMYK', in_row.size, bytes(out_b))
outImage.paste(out_row, (0, row))
row += n_rows
return outImage
def cmyk2rgbImage(PILImage, psrc='C:\\Windows\\System32\\spool\\drivers\\color\\CoatedFOGRA39.icc', pdst='C:\\Windows\\System32\\spool\\drivers\\color\\AdobeRGB1998.icc') :
ctxt = lc.cmsCreateContext(None, None)
white = lc.cmsD50_xyY() # Set white point for D50
dst_profile = lc.cmsOpenProfileFromFile(pdst, 'r')
src_profile = lc.cmsOpenProfileFromFile(psrc, 'r')
transform = lc.cmsCreateTransform(src_profile, lc.TYPE_CMYK_8, dst_profile, lc.TYPE_RGB_8,
lc.INTENT_RELATIVE_COLORIMETRIC, lc.cmsFLAGS_NOCACHE)
n_pixels = PILImage.size[0]
in_comps = 4
out_comps = 3
n_rows = 16
cmyk_in = lc.uint8Array(in_comps * n_pixels * n_rows)
rgb_out = lc.uint8Array(out_comps * n_pixels * n_rows)
outImage = Image.new('RGB', PILImage.size, 'white')
in_row = Image.new('CMYK', (PILImage.size[0], n_rows), 'white')
out_row = Image.new('RGB', (PILImage.size[0], n_rows), 'white')
out_b = bytearray(n_pixels * n_rows * out_comps)
row = 0
while row < PILImage.size[1] :
in_row.paste(PILImage, (0, -row))
data_in = in_row.tobytes('raw')
j = in_comps * n_pixels * n_rows
for i in range(j):
cmyk_in[i] = data_in[i]
lc.cmsDoTransform(transform, cmyk_in, rgb_out, n_pixels * n_rows)
for j in rgb_out :
out_b[j] = rgb_out[j]
out_row = Image.frombytes('RGB', in_row.size, bytes(out_b))
outImage.paste(out_row, (0, row))
row += n_rows
return outImage
答案 2 :(得分:0)
实现此目的的任何人都需要注意的事情:您可能希望采用uint8 CMYK值(0-255)并将它们四舍五入为0-100范围,以更好地匹配大多数颜色选择器和这些值的使用。在这里查看我的代码:https://gist.github.com/mattdesl/ecf305c2f2b20672d682153a7ed0f133