Practical Printer Profiling with Gutenprint

Some time ago I purchased an Epson Stylus Photo R3000 printer, as I wanted to be able to print at A3 size, and get good quality monochrome prints. For a while I struggled a bit to get good quality color photo output from the R3000 using Gutenprint, as it took me a while to figure out which settings proved best for generating and applying ICC profiles.

Sidenote, if you happen to have a R3000 as well and you want to be able to get good results using Gutenprint, you can get some of my profiles here, not all of these profiles have been practically tested. Obviously your milage may vary.

When reading Gutenprint’s documentation they clearly indicated that you should use the “Uncorrected” Color Correction mode, which is very much good advice, as we need deterministic output to be able to generate and apply our ICC profiles in a consistent manner. What kinda threw me off, is that the “Uncorrected” Color Correction mode produces linear gamma output, which practically means very dark output, which the ICC profile is going to need to correct for. And while this is a valid approach, it does generally mean you need to generate a profile using more color patches, which means using more ink and paper for each profile you generate. A more practical approach would be to set Composite Gamma to a value of 1.0, which gamma corrects the output to look more perceptually natural, which consequently means the ICC profile has less to correct for, and thus can be generated using less color patches, and therefore using less ink and paper to do so.

Keep in mind that a printer profile is only valid for a particular combination of Printer, Ink set, Paper, Driver and Settings. Therefore you should document all these facets while generating a profile. This can be as simple as including a similarly named plain text file with each profile you create, for example:

Filename ............: epson_r3000_tecco_photo_matte_230.icc
MD5 Sum .............: 056d6c22ea51104b5e52de8632bd77d4

Paper Type ..........: Tecco Photo Matte 230

Printer Model .......: Epson Stylus Photo R3000
Printer Ink .........: Epson UltraChrome K3 with Vivid Magenta
Printer Firmware ....: AS25E3 (09/11/14)
Printer Driver ......: Gutenprint 5.2.13 (Ubuntu 18.04 LTS)

Color Model .........: RGB
Color Precision .....: Normal
Media Type ..........: Archival Matte Paper
Print Quality .......: Super Photo
Resolution ..........: 1440x1440 DPI
Ink Set .............: Matte Black
Ink Type ............: Standard
Quality Enhancement .: None
Color Correction ....: Uncorrected
Image Type ..........: Photograph
Dither Algorithm ....: EvenTone
Composite Gamma .....: 1.0

You’ll note I’m not using the maximum 5760×2880 resolution Gutenprint supports for this printer, as the quality increase seems almost negligible, and it slows down printing immensely, and might also increase ink consumption with little to show for it.

While the Matte Black (MK) ink set and Archival Matte Paper media type works very well for matte papers, you should probably use Photo Black (PK) ink set and Premium Glossy Photo Paper media type for glossy or Premium Semigloss Photo Paper for pearl, satin & lustre media types.

The following profiling procedure uses only a single sheet of A4 paper, with very decent results, you can use multiple pages by increasing the patch count, the increase in effective output quality will likely be underwhelming though, but your mileage may vary of course.

To proceed you’ll need a spectrophotometer (a colorimeter won’t suffice) supported by ArgyllCMS, like for example the X-Rite Color Munki Photo.

To install ArgyllCMS and other relevant tools on Debian (or one of its derivatives like Ubuntu):

apt-get install argyll liblcms2-utils imagemagick

First we’ll need to generate a set of color patches (we’re including a neutral grey axis, so the profile can more effectively neutralize Epson’s warm tone grey inks):

targen -v -d 3 -G -g 14 -f 210 myprofile
printtarg -v -i CM -h -R 42 -t 360 -M 6 -p A4 myprofile

This results in a TIF file, which you need to print at whatever settings you want to use the profile at. Make sure you let the print dry (and outgas) for an hour at the very least. After the print has dried we’ll need to start measuring the patches using our spectrophotometer:

chartread -v -H myprofile

Once all the patches have been read, we’re ready to generate the actual profile.

colprof -v -D "Tecco Photo Matte 230 for Epson R3000" \
           -C "Copyright 2018 Your Name Here" \
           -Zm -Zr -qm -nc \
           -S /usr/share/color/argyll/ref/sRGB.icm \
           -cmt -dpp myprofile

Note if you’re generating a profile for a glossy or lustre paper type remove the -Zm from the colprof commandline.

Evaluating Your Profile

After generating a custom print profile we can evaluate the profile using xicclu:

xicclu -g -fb -ir myprofile.icc

Looking at the graph above, there are a few things of note, you’ll notice the graph doesn’t touch the lower right corner, which represents a profiles black point, keep in mind that the blackest black any printer can print, still reflects some light, and thus isn’t perfectly black, i.e. 0.

Another point of interest is the curvature of lines, if the graph is bowing significantly to the upper right, it means the media type you have chosen for your profile is causing Gutenprint to put down more ink than the paper you’re using is capable of taking. And conversely if the graph is bowing significantly to the lower left, it means the media type you have chosen for your profile is causing Gutenprint to put down less ink than the paper you’re using is capable of taking. While a profile will compensate for either, having a profile compensate too strongly for either may cause banding artifacts in rare cases especially with an 8-bit workflow. While, I haven’t had a case yet where I needed to, you can use the Density control to adjust the amount of ink put on paper.

Visualizing Printer Gamut

To visualize the effective gamut of your profile you can generate a 3D Lab colorspace graph using iccgamut, which you can view with any modern web browser:

iccgamut -v -w -n myprofile.icc
xdg-open myprofile.x3d.htm

Comparing Gamuts

To compare the gamut of our new custom print profile against a standard working colorspace like sRGB follow these steps:

cp /usr/share/color/argyll/ref/sRGB.icm .
iccgamut -v sRGB.icmiccgamut -v myprofile.icc
viewgam -i -n myprofile.gam sRGB.gam srgb_myprofile
Intersecting volume = 406219.5 cubic units
'epson_r3000_hema_matt_coated_photo_paper_235.gam' volume = 464977.8 cubic units, intersect = 87.36%
'sRGB.gam' volume = 899097.5 cubic units, intersect = 45.18%
xdg-open srgb_myprofile.x3d.htm

From the above output we can conclude that our custom print profile covers about 45% of sRGB, meaning the printer has a gamut that is much smaller than sRGB. However we can also see that sRGB in turn covers about 87% of our custom print profile, which means that 13% of our custom print profile gamut is actually beyond the gamut of sRGB.

This is where gamut mapping comes in. This is where declared rendering intents actually affect how colors outside of the shared gamut is handled.

While a Relative Colorimetric rendering intent limits your prints to the shared area, effectively giving you the smallest practical gamut, it will however offer you the best color accuracy.

A Perceptual rendering intent will scale down colors from an area where a working space profile has a larger gamut (the other 55% of sRGB) into a smaller gamut.

A Saturation rendering intent will also scale up colors from an area where a working space profile has a smaller gamut into a larger gamut (the 13% of our custom print profile).

Manually Preparing Prints using liblcms2-utils

To test your profile, I suggest getting a good test image, like for example from SmugMug, and applying your new profile, using either Perceptual gamut mapping or Relative Colorimetric gamut mapping with Black Point Compensation respectively:

jpgicc -v -o printer.icc -t 0    -q 95 original.jpg print.jpg
jpgicc -v -o printer.icc -t 1 -b -q 95 original.jpg print.jpg

When you open either of the print corrected images, you’ll most likely find they’ll both look awful on your computer’s display, but keep in mind, this is because the images are correcting for printer, driver, ink & paper behavior. If you actually print either image, the printed image should look fairly close to the original image on your computer’s display (presuming you have your display setup properly and calibrated as well).

Manually Preparing Prints using ImageMagick

A more sophisticated way to prepare real images for printing would be using (for example) ImageMagick, these examples below illustrate how you can use ImageMagick to scale an image to a set resolution (360 DPI) for a given paper size, add print sharpening (this is why having a known static resolution is important, otherwise the sharpening would give inconsistent results across different images), then we add a thin black border, and a larger but equidistant (presuming a 3:2 image) white border, and finally we convert the image to our custom print profile:

A4 paper

convert -profile /usr/share/color/argyll/ref/sRGB.icm \
        -resize 2466^ -density 360 -unsharp 2x2+1+0 \
        -bordercolor black -border 28x28 -bordercolor white -border 227x227 \
        -black-point-compensation -intent relative -profile myprofile.icc \
        -strip -sampling-factor 1x1 -quality 95 original.jpg print.jpg

A3 paper

convert -profile /usr/share/color/argyll/ref/sRGB.icm \
        -resize 3487^ -density 360 -unsharp 2x2+1+0 \
        -bordercolor black -border 28x28 -bordercolor white -border 333x333 \
        -black-point-compensation -intent relative -profile myprofile.icc \
        -strip -sampling-factor 1x1 -quality 95 original.jpg print.jpg

A3+ paper

convert -profile /usr/share/color/argyll/ref/sRGB.icm \
        -resize 4320^ -density 360 -unsharp 2x2+1+0 \
        -bordercolor black -border 28x28 -bordercolor white -border 152x152 \
        -black-point-compensation -intent relative -profile myprofile.icc \
        -strip -sampling-factor 1x1 -quality 95 original.jpg print.jpg

Automatically Preparing Prints via colord

While the above method describes a way that gives you a lot of control on how to prepare images for printing, you may also want to use a profile for printing on plain paper, where the input is output of any random application, as opposed to a raster image file that can be very easily preprocessed.

Via colord you can assign a printer an ICC profile that will be automatically applied through cups-filters (pdftoraster), but keep in mind that this profile can only be changed through colormgr (or another colord frontend, like GNOME Control Center) and not through an application’s print dialog, sadly. To avoid messing with driver settings too much, I would suggesting duplicating your printer in CUPS, for example:

  • a printer instance for plain paper prints (with an ICC profile assigned through colord
  • a printer instance for matte color photographic prints (without a profile assigned through colord)
  • a printer instance for (semi)glossy color photographic prints
  • a printer instance for matte black and white photographic prints (likely without a need for a profile at all).
  • a printer instance for (semi)glossy black and white photographic prints (likely without a need for a profile at all).

One caveat of having a printer duplicated in CUPS is that it essentially also creates multiple print queues, which means if you have sent prints to multiple separate queues, you’ll have a race condition where it’s anybody’s guess which queue actually delivers the next print to your single physical printer, which may result in prints coming out in a different order as you had sent them. But it’s my guess that this disadvantage will hardly be noticeable for most people, and very tolerable to most who would notice it.

One thing to keep in mind is that pdftoraster applies an ICC profile by default using a Perceptual rendering intent, which means that out of gamut colors in a source image are scaled to fit inside the the print profile’s gamut. Fundamentally the Perceptual rendering intent makes the tradeoff to keep gradients intact, at the expense of color accuracy, which is most often a fairly sensible thing to do. Given this tidbit of information, and the fact that pdftoraster assumes sRGB input (unless explicitly told otherwise), I’d like to emphasize the importance of passing the -S parameter with an sRGB profile to colprof when generating print profiles for on Linux.

To assign an ICC profile to be applied automatically by cups-filters:

sudo cp navigator_colour_documents_120.icc /var/lib/colord/icc/navigator_colour_documents_120.icc
colormgr import-profile /var/lib/colord/icc/navigator_colour_documents_120.icc
colormgr find-profile-by-filename /var/lib/colord/icc/navigator_colour_documents_120.icc
colormgr get-devices-by-kind printer
colormgr device-add-profile \
         /org/freedesktop/ColorManager/devices/cups_EPSON_Epson_Stylus_Photo_R3000 \
         /org/freedesktop/ColorManager/profiles/icc_c43e7ce085212ba8f85ae634085ecfd3

More on Gutenprint media types

In contrast to commercial printer drivers, Gutenprint gives us the opportunity to peek under the covers, and find out more about the different media types Gutenprint supports for your printer, first lookup your printers model number:

$ grep 'R3000' /usr/share/gutenprint/5.2/xml/printers.xml 
<printer ... name="Epson Stylus Photo R3000" driver="escp2-r3000" ... model="115" ...

Then find the relevant media definition file:

$ grep 'media src' /usr/share/gutenprint/5.2/xml/escp2/model/model_115.xml 
<media src="escp2/media/f360_ultrachrome_k3v.xml"/>

Finally you can dig through the relevant media type definitions, where the Density parameter is of particular interest:

$ less /usr/share/gutenprint/5.2/xml/escp2/media/f360_ultrachrome_k3v.xml
<paper ... text="Plain Paper" ... PreferredInkset="ultra3matte">
  <ink ... name="ultra3matte" text="UltraChrome Matte Black">
    <parameter type="float" name="Density">0.720000</parameter>
<paper ... text="Archival Matte Paper" ... PreferredInkset="ultra3matte">
  <ink ... name="ultra3matte" text="UltraChrome Matte Black">
    <parameter type="float" name="Density">0.920000</parameter>
<paper ... text="Premium Glossy Photo Paper" ... PreferredInkset="ultra3photo">
  <ink ... name="ultra3photo" text="UltraChrome Photo Black">
    <parameter type="float" name="Density">0.720000</parameter>
<paper ... text="Premium Semigloss Photo Paper" ... PreferredInkset="ultra3photo">
  <ink ... name="ultra3photo" text="UltraChrome Photo Black">
    <parameter type="float" name="Density">0.720000</parameter>
<paper ... text="Photo Paper" ... PreferredInkset="ultra3photo">
  <ink ... name="ultra3photo" text="UltraChrome Photo Black">
    <parameter type="float" name="Density">1.000000</parameter> 

Dedicated Grey Neutralization Profile

As mentioned earlier, the Epson R3000 uses warm tone grey inks, which results in very pleasant true black & white images, without any color inks used, at least when Gutenprint is told to print in Greyscale mode.

If, unlike me, you don’t like the warm tone effect, applying the ICC we generated should neutralize it mostly, but possibly not perfectly, which is fine for neutral area’s in color prints, but may be less satisfactory for proper black & white prints.

While I haven’t done any particular testing on this issue, you may want to consider doing a second profile dedicated and tuned to grey neutralization, just follow the normal profiling procedure with the following target generation command instead:

targen -v -d 3 -G -g 64 -f 210 -c previous_color_profile.icc -A 1.0 -N 1.0 grey_neutral_profile

Obviously you’ll need to use this particular profile in RGB color mode, even though your end goal may be monochrome, given that the profile needs to use color inks to compensate for the warm tone grey inks.