Skip to content

Commit e75b3d1

Browse files
brettnakTurboGit
authored andcommitted
print: fix color management when using printer ICC profiles
When a printer ICC profile is selected, darktable applies the color conversion via LittleCMS but fails to communicate this to the downstream CUPS pipeline, causing incorrect color output. This commit fixes the issue on both Linux and macOS: 1. The printer.profile field on the print info struct was never populated from the user's profile selection, so the cm-calibration CUPS option was always set to "false". Fixed by propagating the profile selection into printer.profile before calling dt_print_file(). 2. On Linux, cm-calibration=true tells pdftoraster to skip its own color management, preventing double conversion. 3. On macOS, cgpdftoraster ignores cm-calibration entirely. Two additional fixes are needed: - Embed the ICC profile in the PDF so cgpdftoraster knows the pixel data is not sRGB (without this, it misinterprets the already-converted data). - Send AP_ColorMatchingMode=AP_ApplicationColorMatching (both dot and underscore variants) to tell cgpdftoraster and the printer driver that the application already handled color matching. Note: on Linux, the ICC profile must NOT be embedded in the PDF — Poppler (inside pdftoraster) would see the ICCBased color space and convert the data back to sRGB, undoing the LittleCMS conversion. Tested on macOS with Canon Pixma Pro-100 against Capture One output.
1 parent af59b5d commit e75b3d1

2 files changed

Lines changed: 46 additions & 7 deletions

File tree

src/common/cups_print.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,12 +547,36 @@ void dt_print_file(const dt_imgid_t imgid,
547547

548548
cupsFreeDests(num_dests, dests);
549549

550-
// if we have a profile, disable cm on CUPS, this is important as dt does the cm
550+
// When a printer ICC profile is selected, tell CUPS to skip its
551+
// own color management — darktable already did the conversion
552+
// via LittleCMS, and the ICC profile is embedded in the PDF.
553+
//
554+
// Linux: cm-calibration=true causes pdftoraster to set cm_disabled=1,
555+
// skipping its own color management.
556+
//
557+
// macOS: cgpdftoraster ignores cm-calibration. Instead we send
558+
// AP_ColorMatchingMode=AP_ApplicationColorMatching which
559+
// tells both cgpdftoraster and the printer driver that the
560+
// application already handled color matching.
551561

552562
num_options = cupsAddOption("cm-calibration",
553563
*pinfo->printer.profile ? "true" : "false",
554564
num_options, &options);
555565

566+
#ifdef __APPLE__
567+
if(*pinfo->printer.profile)
568+
{
569+
// dot-notation variant appears to be legacy but is observed in
570+
// print jobs from other macOS applications
571+
num_options = cupsAddOption("AP.ColorMatchingMode",
572+
"AP_ApplicationColorMatching",
573+
num_options, &options);
574+
num_options = cupsAddOption("AP_ColorMatchingMode",
575+
"AP_ApplicationColorMatching",
576+
num_options, &options);
577+
}
578+
#endif
579+
556580
// media to print on
557581

558582
num_options = cupsAddOption("media", pinfo->paper.name, num_options, &options);

src/libs/print_settings.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ static void _create_pdf(dt_job_t *job,
445445

446446
const float page_width = dt_pdf_mm_to_point(width);
447447
const float page_height = dt_pdf_mm_to_point(height);
448-
const int icc_id = 0;
448+
int icc_id = 0;
449449

450450
dt_pdf_image_t *pdf_image[MAX_IMAGE_PER_PAGE];
451451

@@ -454,11 +454,19 @@ static void _create_pdf(dt_job_t *job,
454454
params->prt.printer.resolution,
455455
DT_PDF_STREAM_ENCODER_FLATE);
456456

457-
/*
458-
// ??? should a profile be embedded here?
459-
if(*printer_profile)
460-
icc_id = dt_pdf_add_icc(pdf, printer_profile);
461-
*/
457+
#ifdef __APPLE__
458+
// On macOS, embed the printer ICC profile in the PDF so the
459+
// already-converted pixel data is correctly tagged with its actual
460+
// color space. Without this, cgpdftoraster assumes DeviceRGB = sRGB
461+
// and misinterprets the data.
462+
//
463+
// On Linux this must NOT be done — Poppler (inside pdftoraster) would
464+
// see the ICCBased color space and convert the data back to sRGB,
465+
// undoing the LittleCMS conversion. Linux uses cm-calibration instead.
466+
if(params->p_icc_profile && *params->p_icc_profile)
467+
icc_id = dt_pdf_add_icc(pdf, params->p_icc_profile);
468+
#endif
469+
462470
int32_t count = 0;
463471

464472
for(int k=0; k<imgs.count; k++)
@@ -779,6 +787,13 @@ static void _print_button_clicked(GtkWidget *widget, dt_lib_module_t *self)
779787
params->p_icc_intent = ps->v_pintent;
780788
params->black_point_compensation = ps->v_black_point_compensation;
781789

790+
// Propagate the printer profile selection so dt_print_file() can
791+
// tell CUPS to skip color management when dt already did the
792+
// ICC conversion. See cups_print.c for platform-specific details.
793+
if(ps->v_piccprofile && *ps->v_piccprofile)
794+
g_strlcpy(params->prt.printer.profile, ps->v_piccprofile,
795+
sizeof(params->prt.printer.profile));
796+
782797
dt_control_add_job(DT_JOB_QUEUE_USER_EXPORT, job);
783798
}
784799

0 commit comments

Comments
 (0)