How to improve color consistency of bitmap pictures from native format to target pdf file?
Disclaimer: I know next to nothing about colour management, but find the subject interesting. I'm confused by some of the stuff below. Maybe someone with more knowledge can shed some light...
By googling, I found two advices on this issue.
Update: Based on michal-h21s suggestion that pdftex
supports adding a color profile to an embedded image, I could work out another solution. See section Attach Color Profile to Embedded Image below.
Convert to PDF
See http://webstaff.itn.liu.se/~karlu20/div/howto/LaTeX_colour_management.php
There, the advice is basically to convert the image (including a profile) to PDF and embed the PDF.
To test, I downloaded the example image with ProPhoto profile.
identify -verbose butterfly_ProPhoto.png
gives
Profile-icc: 566 bytes
Description: SCARSE: Kodak ProPhoto RGB
Manufacturer: SCARSE: Kodak ProPhoto RGB
Model: SCARSE: Kodak ProPhoto RGB
Copyright: Copyright (C) 1999-2005 Scarse Project
so apparently the profile is found by ImageMagick. Then I converted the image with convert butterfly_ProPhoto.png butterfly_ProPhoto.pdf
. From the docs ImageMagick can cope with color profiles, and identify -verbose butterfly_ProPhoto.pdf
gives
Profile-icc: 2576 bytes
Description: Artifex Software sRGB ICC Profile
Manufacturer: Artifex Software sRGB ICC Profile
Model: Artifex Software sRGB ICC Profile
Copyright: Copyright Artifex Software 2011
So apparently the PDF contains a profile, but it was converted (why?).
Testing the profile embedding with
\documentclass[a4paper]{article}
\usepackage{graphicx}
\begin{document}
\noindent
\includegraphics[width=\linewidth]{butterfly_ProPhoto.png}
\noindent
\includegraphics[width=\linewidth]{butterfly_ProPhoto.pdf}
\end{document}
and viewing with acrobat reader, I don't see a difference:
Furthermore, the result on my screen looks completely different from the example PDF given on the linked page, so apparently I did something wrong by just using convert.
A further hint convert
doesn't cut it comes from this example containing an image with a GBR profile.
Converting Peppers_withGBRprofile.jpg
to PDF and viewing in acrobat reader like above gives
The same is displayed in Acrobat Professional, btw.
So apparently it is indeed impossible to use convert
to successfully convert profiled images to PDF for embedding with pdftex
, though the ImageMagic doc and identify
results seem to suggest otherwise. Could someone elaborate?
Second try: Convert to PDF with Acrobat Professional
Disappointed with no success at all trying to convert to PDF with ImageMagick, I tried the same procedure converting the test images (PNG and JPG) to PDF with the "create PDF" feature of Acrobat professional, and voilá:
So I can conclude that converting a profiled image into a PDF with embedded profile indeed works, but not with the ImageMagick based toolchain I've used on my Ubuntu Linux system.
The page I linked to in the beginning mentions that apparently the only tool capable of doing this under Linux is Scribus which I have not tried here.
Embedding a colour profile in the PDF
See http://compgroups.net/comp.text.tex/making-a-cmyk-pdf/153995
This advice basically is to embed a colour profile in the PDF.
So, taking the GBR example above, I extracted the ICC profile with
convert Peppers_withGBRprofile.jpg gbr.icm
and embedded the profile into the PDF with the following test file:
\documentclass[a4paper]{article}
\usepackage{graphicx}
\immediate\pdfobj stream attr{/N 4} file{gbr.icm}
\pdfcatalog{%
/OutputIntents [ <<
/Type /OutputIntent
/S/GTS_PDFA1
/DestOutputProfile \the\pdflastobj\space 0 R
/OutputConditionIdentifier (Adobe GBR (2004))
/Info(Adobe GBR (2004))
>> ]
}
\begin{document}
\noindent
\includegraphics[width=\linewidth]{Peppers_withGBRprofile.jpg}
\noindent
\includegraphics[width=\linewidth]{Peppers_withGBRprofile.pdf}
\end{document}
Frustratingly, with acrobat reader on Ubuntu, the PDF displays exactly as (wrongly):
But in Acrobat Professional, I get the correct display:
So it seems that embedding a color profile in the PDF does work (on both JPG and PDF inclusions), but not with acrobat reader on Linux.
Furthermore, this "solution" means the embedded profile simply becomes the base profile for the whole document, so one profile will be applied to all images (which do not themselves contain a profile). So embedding both test images (both of which contain different profiles), the result is
In the color proofing dialog you can also see that the GBR profile is shown as the document profile. This is a further aspect that this advice isn't so useful, because I could assign any other profile right there in the Acrobat dialog (changing the color display of both images accordingly).
Attach Color Profile to Embedded Image
Based on the advice of michal-h21 in his answer I looked into the pdftex
doc and found that the \pdfximage
primitive indeed supports a keyword colorspace
which will associate the corresponding object with the embedded image.
Based on this, I could make the following patch to the pdftex
driver of the graphics
package (including example):
\documentclass[a4paper]{article}
\usepackage{graphicx}
\usepackage{etoolbox}
\makeatletter
\let\GPT@colorspacefile\ltx@empty
\define@key{Gin}{colorspacefile}{\def\GPT@colorspacefile{#1}}%
\patchcmd\Gread@@pdftex
{\pdfximage\GPT@RuleAttr}
{%
\ifx\GPT@colorspacefile\ltx@empty
\else
\immediate\pdfobj stream attr{/N 4} file{\GPT@colorspacefile}%
\@tempcnta\the\pdflastobj
\fi
\pdfximage\GPT@RuleAttr
\ifx\GPT@colorspacefile\ltx@empty
\else
colorspace \@tempcnta
\fi
}%
{}{}
\makeatother
\begin{document}
\noindent
\includegraphics[width=.5\linewidth]{Peppers_withGBRprofile.jpg}\includegraphics[width=.5\linewidth,colorspacefile={gbr.icm}]{./Peppers_withGBRprofile.jpg}
\noindent
\includegraphics[width=.5\linewidth]{butterfly_ProPhoto.png}\includegraphics[width=.5\linewidth,colorspacefile={prophoto.icm}]{./butterfly_ProPhoto.png}
\end{document}
which gives
I got the profiles directly from the images with
convert Peppers_withGBRprofile.jpg gbr.icm
convert butterfly_ProPhoto.png prophoto.icm
To me, this seems to be the best solution because it allows to associate each image with its own color profile without needing a non-trivial conversion step.
Interestingly, you can see on the test image that it also works with PNG images, although the pdftex
documentation claims this should not work.
Note that the "integration" given above is a proof-of-concept only and should not be used for production purposes. First, one should have some "caching" mechanism for color profiles to avoid embedding a profile more than once. Secondly, if the same file should be used with different profiles (as in this example), this could clash with the internal caching mechanism which will embed each image only once. Note the trick with using the ./
filename prefix to make the same file appear as two different files.
Conclusions
From this round of tests, I conclude that
- Converting images to PDF with embedded color profile works, but I couldn't get it to work with
convert
from ImageMagick (version 6.7.7-10). So the number of workable tools for Linux seems to be limited (the linked article mentions Scribus, which I did not try). - Embedding an ICC profile in the PDF generated by
pdftex
demonstrably works, but it seems acrobat reader (version 9.5.5) on Ubuntu has problems interpreting such an embedded profile, while Acrobat Professional hasn't. Furthermore, this adds "only" a global profile to the whole PDF document, without a possibility to differentiate between different images. - Using the
colorspace
keyword of\pdfximage
, it is possible to attach a color profile to any embedded image. - On the whole, the third alternative seems to be the best solution, because it also works with acrobat reader on Linux, every image can have its own profile, and no rare tool for converting images is required.
It seems that in PDF format doesn't suffice that included image contains ICC profile, but this profile must be included as a standalone object and the image must reference this object.
I think there is a low level support for this feature in pdftex
(but only for jpeg images, regarding to the manual) and luatex
, but the graphicx
package doesn't have support for this.
More user friendly (at least for me :)) possibility to include a icc
profile is using luatex
's img
library. I created small library called collorspaces.lua
:
local m = {}
local colorspaces = {}
local images = {}
function create_profile(filename)
local icc = pdf.immediateobj("streamfile", filename, [[
/N 4
/Alernate/DeviceRGB]])
local profile = pdf.immediateobj("[/ICCBased "..icc.." 0 R]")
return profile
end
function load_image(filename, attributes)
local exists =images[filename]
if exists then return exists end
local profile_file = filename:gsub("[%w]+$","icm")
local command = "convert ".. filename .." " .. profile_file
local conversion_status = os.execute(command)
local profile = nil
local img_attr = {filename = filename}
if conversion_status == 0 then
local icc_file = io.open(profile_file,"r")
local icc = icc_file:read("*all")
icc_file:close()
local hash = md5.sumhexa(icc)
profile = colorspaces[hash]
if not profile then
profile = create_profile(profile_file)
end
img_attr.colorspace= profile
colorspaces[hash]=profile
end
local image = img.scan(img_attr)
images[filename] = image
return image
end
local function write_image(image)
return img.write(image)
end
local function include_image(image_name)
local image = load_image(image_name)
write_image(image)
end
--load_image("gbr.jpg")
--load_image("rgb.jpg")
m.load_image = load_image
m.write_image = write_image
m.include_image = include_image
return m
main function is load_image
, where icc
profile is extracted using imagemagick's convert
utility, then hash of this file is calculated, to prevent multiple inclusions of same profile to the pdf file, and if the profile wasn't used yet, it is included using create_profile
function. Then the image is loaded. There are two more functions, write_image
will output the image to the output stream, and include_image
which load and write image.
Now some sample document:
\documentclass{article}
\usepackage[]{graphicx}
\pdfcompresslevel=0
\directlua{%
cs = require "colorspaces"
}
\def\myinc#1{\mbox{\directlua{cs.include_image "#1"}}}
\begin{document}
\setlength\parindent{0pt}
Rgb file without profile\\
\myinc{rgb.jpg}
Rgb file with profile\\
\myinc{gbr.jpg}
Rgb file with profile and includegraphics\\
\includegraphics{gbr.jpg}
Resize image\\
\resizebox{\linewidth}{!}{\myinc{gbr.jpg}}
\end{document}
You must run it with
lualatex -shell-escape filename
otherwise convert
command couldn't be run!
There are two images, gbr.jpg
and rgb.jpg
, these are peppers from Stephan's samples. First contains ICC profile, second doesn't. The result:
As you can see, there is slight difference in first two images, which were included using our function, third, using \includegraphics
is completely wrong. Last example shows how to resize the image.
If you doesn't want to use lualatex
, you can convert your images to pdf
with this script imgtopdf.lua
:
#!/usr/bin/env texlua
local filename = arg[1]
if not filename then
print "Usage imgtopdf filename"
return false
end
local jobname = filename:gsub("%.%w+$","")
local tpl = [[\documentclass{standalone}
\directlua{cs = require "colorspaces"}
\def\myinc#1{\directlua{cs.include_image "#1"}}
\begin{document}
\myinc{%s}
\end{document}
]]
local lualatex = io.popen("lualatex -shell-escape -jobname="..jobname,"w")
lualatex:write(string.format(tpl,filename))
lualatex:close()
Run with
texlua imgtopdf.lua imagename