Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
cups_print.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2014-2015, 2017-2018, 2020-2021 Pascal Obry.
4 Copyright (C) 2015 Jérémy Rosen.
5 Copyright (C) 2015, 2019-2020 parafin.
6 Copyright (C) 2015-2016 Roman Lebedev.
7 Copyright (C) 2015-2018 Tobias Ellinghaus.
8 Copyright (C) 2017-2018, 2022 Dan Torop.
9 Copyright (C) 2019 Heiko Bauke.
10 Copyright (C) 2019 jakubfi.
11 Copyright (C) 2019 luzpaz.
12 Copyright (C) 2021 Ralf Brown.
13 Copyright (C) 2021 RSL.
14 Copyright (C) 2022 Martin Bařinka.
15
16 darktable is free software: you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
20
21 darktable is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with darktable. If not, see <http://www.gnu.org/licenses/>.
28*/
29
30#include "common/utility.h"
31#include "control/control.h"
32#include <glib/gstdio.h>
33#include "system/macros.h"
34#include "system/mem_alloc.h"
35#include "common/logging.h"
36#include "common/paths.h"
37#include <cups/cups.h>
38#include <cups/ppd.h>
39#include <glib.h>
40#include <stdio.h>
41#ifdef __APPLE__
42#include <AvailabilityMacros.h>
43#endif
44
46#include "common/pdf.h"
47#include "cups_print.h"
48
49// enable weak linking in libcups on macOS
50#if defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 && ((CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 6) || CUPS_VERSION_MAJOR > 1)
51extern int cupsEnumDests() __attribute__((weak_import));
52#endif
53#if defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 && ((CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 7) || CUPS_VERSION_MAJOR > 1)
54extern http_t *cupsConnectDest() __attribute__((weak_import));
55extern cups_dinfo_t *cupsCopyDestInfo() __attribute__((weak_import));
56extern int cupsGetDestMediaCount() __attribute__((weak_import));
57extern int cupsGetDestMediaByIndex() __attribute__((weak_import));
58extern void cupsFreeDestInfo() __attribute__((weak_import));
59#endif
60
61#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
62// some platforms are starting to provide CUPS 2.2.9 and there the
63// CUPS API deprecated routines ate now flagged as such and reported as
64// warning preventing the compilation.
65//
66// this seems wrong and PPD should be removed from this unit. but there
67// still one missing piece discussed with the CUPS maintainers about the
68// way to get media-type using the IPP API. nothing close to working at
69// this stage, so instead of breaking the compilation on platforms using
70// recent CUPS version we kill the warning.
71
72typedef struct dt_prtctl_t
73{
74 void (*cb)(dt_printer_info_t *, void *);
75 void *user_data;
77
78// initialize the pinfo structure
80{
81 memset(&pinfo->printer, 0, sizeof(dt_printer_info_t));
82 memset(&pinfo->page, 0, sizeof(dt_page_setup_t));
83 memset(&pinfo->paper, 0, sizeof(dt_paper_info_t));
86 *pinfo->printer.profile = '\0';
87}
88
89void dt_get_printer_info(const char *printer_name, dt_printer_info_t *pinfo)
90{
91 cups_dest_t *dests;
92 const int num_dests = cupsGetDests(&dests);
93 cups_dest_t *dest = cupsGetDest(printer_name, NULL, num_dests, dests);
94
95 if (dest)
96 {
97 const char *PPDFile = cupsGetPPD (printer_name);
98 g_strlcpy(pinfo->name, dest->name, MAX_NAME);
99 ppd_file_t *ppd = ppdOpenFile(PPDFile);
100
101 if (ppd)
102 {
103 ppdMarkDefaults(ppd);
104 cupsMarkOptions(ppd, dest->num_options, dest->options);
105
106 // first check if this is turboprint drived printer, two solutions:
107 // 1. ModelName contains TurboPrint
108 // 2. zedoPrinterDriver exists
109 ppd_attr_t *attr = ppdFindAttr(ppd, "ModelName", NULL);
110
111 if (attr)
112 {
113 pinfo->is_turboprint = strstr(attr->value, "TurboPrint") != NULL;
114 }
115
116 // hardware margins
117
118 attr = ppdFindAttr(ppd, "HWMargins", NULL);
119
120 if (attr)
121 {
122 // scanf use local number format and PPD has en numbers
124
125 sscanf(attr->value, "%lf %lf %lf %lf",
126 &pinfo->hw_margin_left, &pinfo->hw_margin_bottom,
127 &pinfo->hw_margin_right, &pinfo->hw_margin_top);
128
133 }
134
135 // default resolution
136
137 attr = ppdFindAttr(ppd, "DefaultResolution", NULL);
138
139 if (attr)
140 {
141 char *x = strstr(attr->value, "x");
142
143 if (x)
144 sscanf (x+1, "%ddpi", &pinfo->resolution);
145 else
146 sscanf (attr->value, "%ddpi", &pinfo->resolution);
147 }
148 else
149 pinfo->resolution = 300;
150
151 while(pinfo->resolution>360)
152 pinfo->resolution /= 2.0;
153
154 ppdClose(ppd);
155 g_unlink(PPDFile);
156 }
157 }
158
159 cupsFreeDests(num_dests, dests);
160}
161
162static int _dest_cb(void *user_data, unsigned flags, cups_dest_t *dest)
163{
164 const dt_prtctl_t *pctl = (dt_prtctl_t *)user_data;
165 const char *psvalue = cupsGetOption("printer-state", dest->num_options, dest->options);
166
167 // check that the printer is ready
168 if (psvalue!=NULL && strtol(psvalue, NULL, 10) < IPP_PRINTER_STOPPED)
169 {
171 memset(&pr, 0, sizeof(pr));
172 dt_get_printer_info(dest->name, &pr);
173 if (pctl->cb) pctl->cb(&pr, pctl->user_data);
174 dt_print(DT_DEBUG_PRINT, "[print] new printer %s found\n", dest->name);
175 }
176 else
177 dt_print(DT_DEBUG_PRINT, "[print] skip printer %s as stopped\n", dest->name);
178
179 return 1;
180}
181
182static int _cancel = 0;
183
185{
187 int res;
188#if ((CUPS_VERSION_MAJOR == 1) && (CUPS_VERSION_MINOR >= 6)) || CUPS_VERSION_MAJOR > 1
189#if defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
190 if (!IS_NULL_PTR(&cupsEnumDests))
191#endif
192 res = cupsEnumDests(CUPS_MEDIA_FLAGS_DEFAULT, 30000, &_cancel, 0, 0, _dest_cb, pctl);
193#if defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
194 else
195#endif
196#endif
197#if defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 || !(((CUPS_VERSION_MAJOR == 1) && (CUPS_VERSION_MINOR >= 6)) || CUPS_VERSION_MAJOR > 1)
198 {
199 cups_dest_t *dests;
200 const int num_dests = cupsGetDests(&dests);
201 for (int k=0; k<num_dests; k++)
202 {
203 _dest_cb((void *)pctl, 0, &dests[k]);
204 }
205 cupsFreeDests(num_dests, dests);
206 res=1;
207 }
208#endif
209 return !res;
210}
211
213{
214 _cancel = 1;
215}
216
217void dt_printers_discovery(void (*cb)(dt_printer_info_t *pr, void *user_data), void *user_data)
218{
219 // asynchronously checks for available printers
220 dt_job_t *job = dt_control_job_create(&_detect_printers_callback, "detect connected printers");
221 if(job)
222 {
223 dt_prtctl_t *prtctl = g_malloc0(sizeof(dt_prtctl_t));
224
225 prtctl->cb = cb;
226 prtctl->user_data = user_data;
227
228 dt_control_job_set_params(job, prtctl, g_free);
230 }
231}
232
233static gboolean paper_exists(GList *papers, const char *name)
234{
235 if (strstr(name,"custom_") == name)
236 return TRUE;
237
238 for(GList *p = papers; p; p = g_list_next(p))
239 {
240 const dt_paper_info_t *pi = (dt_paper_info_t*)p->data;
241 if (!strcmp(pi->name,name) || !strcmp(pi->common_name,name))
242 return TRUE;
243 }
244 return FALSE;
245}
246
247dt_paper_info_t *dt_get_paper(GList *papers, const char *name)
248{
249 dt_paper_info_t *result = NULL;
250
251 for(GList *p = papers; p; p = g_list_next(p))
252 {
253 dt_paper_info_t *pi = (dt_paper_info_t*)p->data;
254 if (!strcmp(pi->name,name) || !strcmp(pi->common_name,name))
255 {
256 result = pi;
257 break;
258 }
259 }
260 return result;
261}
262
263static gint
264sort_papers (gconstpointer p1, gconstpointer p2)
265{
266 const dt_paper_info_t *n1 = (dt_paper_info_t *)p1;
267 const dt_paper_info_t *n2 = (dt_paper_info_t *)p2;
268 const int l1 = strlen(n1->common_name);
269 const int l2 = strlen(n2->common_name);
270 return l1==l2 ? strcmp(n1->common_name, n2->common_name) : (l1 < l2 ? -1 : +1);
271}
272
273GList *dt_get_papers(const dt_printer_info_t *printer)
274{
275 const char *printer_name = printer->name;
276 GList *result = NULL;
277
278#if ((CUPS_VERSION_MAJOR == 1) && (CUPS_VERSION_MINOR >= 7)) || CUPS_VERSION_MAJOR > 1
279#if defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
280 if (!IS_NULL_PTR(&cupsConnectDest) && !IS_NULL_PTR(&cupsCopyDestInfo) && !IS_NULL_PTR(&cupsGetDestMediaCount) &&
281 !IS_NULL_PTR(&cupsGetDestMediaByIndex) && !IS_NULL_PTR(&cupsFreeDestInfo))
282#endif
283 {
284 cups_dest_t *dests;
285 const int num_dests = cupsGetDests(&dests);
286 cups_dest_t *dest = cupsGetDest(printer_name, NULL, num_dests, dests);
287
288 int cancel = 0; // important
289
290 char resource[1024];
291
292 if (dest)
293 {
294 http_t *hcon = cupsConnectDest(dest, 0, 2000, &cancel, resource, sizeof(resource), NULL, (void *)NULL);
295
296 if (hcon)
297 {
298 cups_size_t size;
299 cups_dinfo_t *info = cupsCopyDestInfo (hcon, dest);
300 const int count = cupsGetDestMediaCount(hcon, dest, info, CUPS_MEDIA_FLAGS_DEFAULT);
301 for (int k=0; k<count; k++)
302 {
303 if (cupsGetDestMediaByIndex(hcon, dest, info, k, CUPS_MEDIA_FLAGS_DEFAULT, &size))
304 {
305 if (size.width!=0 && size.length!=0 && !paper_exists(result, size.media))
306 {
307 pwg_media_t *med = pwgMediaForPWG (size.media);
308 char common_name[MAX_NAME] = { 0 };
309
310 if (med->ppd)
311 g_strlcpy(common_name, med->ppd, sizeof(common_name));
312 else
313 g_strlcpy(common_name, size.media, sizeof(common_name));
314
315 dt_paper_info_t *paper = (dt_paper_info_t*)malloc(sizeof(dt_paper_info_t));
316 g_strlcpy(paper->name, size.media, sizeof(paper->name));
317 g_strlcpy(paper->common_name, common_name, sizeof(paper->common_name));
318 paper->width = (double)size.width / 100.0;
319 paper->height = (double)size.length / 100.0;
320 result = g_list_append (result, paper);
321
323 "[print] new media paper %4d %6.2f x %6.2f (%s) (%s)\n",
324 k, paper->width, paper->height, paper->name, paper->common_name);
325 }
326 }
327 }
328
329 cupsFreeDestInfo(info);
330 httpClose(hcon);
331 }
332 else
333 dt_print(DT_DEBUG_PRINT, "[print] cannot connect to printer %s (cancel=%d)\n", printer_name, cancel);
334 }
335
336 cupsFreeDests(num_dests, dests);
337 }
338#endif
339
340 // check now PPD page sizes
341
342 const char *PPDFile = cupsGetPPD(printer_name);
343 ppd_file_t *ppd = ppdOpenFile(PPDFile);
344
345 if (ppd)
346 {
347 ppd_size_t *size = ppd->sizes;
348
349 for (int k=0; k<ppd->num_sizes; k++)
350 {
351 if (size->width!=0 && size->length!=0 && !paper_exists(result, size->name))
352 {
353 dt_paper_info_t *paper = (dt_paper_info_t*)malloc(sizeof(dt_paper_info_t));
354 g_strlcpy(paper->name, size->name, MAX_NAME);
355 g_strlcpy(paper->common_name, size->name, MAX_NAME);
356 paper->width = (double)dt_pdf_point_to_mm(size->width);
357 paper->height = (double)dt_pdf_point_to_mm(size->length);
358 result = g_list_append (result, paper);
359
361 "[print] new ppd paper %4d %6.2f x %6.2f (%s) (%s)\n",
362 k, paper->width, paper->height, paper->name, paper->common_name);
363 }
364 size++;
365 }
366
367 ppdClose(ppd);
368 g_unlink(PPDFile);
369 }
370
371 result = g_list_sort_with_data (result, (GCompareDataFunc)sort_papers, NULL);
372 return result;
373}
374
376{
377 const char *printer_name = printer->name;
378 GList *result = NULL;
379
380 // check now PPD media type
381
382 const char *PPDFile = cupsGetPPD(printer_name);
383 ppd_file_t *ppd = ppdOpenFile(PPDFile);
384
385 if (ppd)
386 {
387 ppd_option_t *opt = ppdFindOption(ppd, "MediaType");
388
389 if (opt)
390 {
391 ppd_choice_t *choice = opt->choices;
392
393 for (int k=0; k<opt->num_choices; k++)
394 {
395 dt_medium_info_t *media = (dt_medium_info_t*)malloc(sizeof(dt_medium_info_t));
396 g_strlcpy(media->name, choice->choice, MAX_NAME);
397 g_strlcpy(media->common_name, choice->text, MAX_NAME);
398 result = g_list_prepend (result, media);
399
400 dt_print(DT_DEBUG_PRINT, "[print] new media %2d (%s) (%s)\n", k, media->name, media->common_name);
401 choice++;
402 }
403 }
404 }
405
406 ppdClose(ppd);
407 g_unlink(PPDFile);
408
409 return g_list_reverse(result); // list was built in reverse order, so un-reverse it
410}
411
412dt_medium_info_t *dt_get_medium(GList *media, const char *name)
413{
414 dt_medium_info_t *result = NULL;
415
416 for(GList *m = media; m; m = g_list_next(m))
417 {
418 dt_medium_info_t *mi = (dt_medium_info_t*)m->data;
419 if (!strcmp(mi->name, name) || !strcmp(mi->common_name, name))
420 {
421 result = mi;
422 break;
423 }
424 }
425 return result;
426}
427
428void dt_print_file(const int32_t imgid, const char *filename, const char *job_title, const dt_print_info_t *pinfo)
429{
430 // first for safety check that filename exists and is readable
431
432 if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
433 {
434 dt_control_log(_("file `%s' to print not found for image %d on `%s'"), filename, imgid, pinfo->printer.name);
435 return;
436 }
437
438 cups_option_t *options = NULL;
439 int num_options = 0;
440
441 // for turboprint drived printer, use the turboprint dialog
442 if (pinfo->printer.is_turboprint)
443 {
444 const char *tp_intent_name[] = { "perception_0", "colorimetric-relative_1", "saturation_1", "colorimetric-absolute_1" };
445 char tmpfile[DT_PATH_MAX] = { 0 };
446
447 dt_loc_get_tmp_dir(tmpfile, sizeof(tmpfile));
448 g_strlcat(tmpfile, "/dt_cups_opts_XXXXXX", sizeof(tmpfile));
449
450 gint fd = g_mkstemp(tmpfile);
451 if(fd == -1)
452 {
453 dt_control_log(_("failed to create temporary file for printing options"));
454 fprintf(stderr, "failed to create temporary pdf for printing options\n");
455 return;
456 }
457 close(fd);
458
459 // ensure that intent is in the range, may happen if at some point we add new intent in the list
460 const int intent = (pinfo->printer.intent < 4) ? pinfo->printer.intent : 0;
461
462 // spawn turboprint command
463 gchar * argv[15] = { 0 };
464
465 argv[0] = "turboprint";
466 argv[1] = g_strdup_printf("--printer=%s", pinfo->printer.name);
467 argv[2] = "--options";
468 argv[3] = g_strdup_printf("--output=%s", tmpfile);
469 argv[4] = "-o";
470 argv[5] = "copies=1";
471 argv[6] = "-o";
472 argv[7] = g_strdup_printf("PageSize=%s", pinfo->paper.common_name);
473 argv[8] = "-o";
474 argv[9] = "InputSlot=AutoSelect";
475 argv[10] = "-o";
476 argv[11] = g_strdup_printf("zedoIntent=%s", tp_intent_name[intent]);
477 argv[12] = "-o";
478 argv[13] = g_strdup_printf("MediaType=%s", pinfo->medium.name);
479 argv[14] = NULL;
480
481 gint exit_status = 0;
482
483 g_spawn_sync(NULL, argv, NULL,
484 G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
485 NULL, NULL, NULL, NULL, &exit_status, NULL);
486
487 dt_free(argv[1]);
488 dt_free(argv[3]);
489 dt_free(argv[7]);
490 dt_free(argv[11]);
491 dt_free(argv[13]);
492
493 if(exit_status==0)
494 {
495 FILE *stream = g_fopen(tmpfile, "rb");
496
497 while(1)
498 {
499 char optname[100];
500 char optvalue[100];
501 const int ropt = fscanf(stream, "%*s %99[^= ]=%99s", optname, optvalue);
502
503 // if we parsed an option name=value
504 if (ropt==2)
505 {
506 char *v = optvalue;
507
508 // remove possible single quote around value
509 if (*v == '\'') v++;
510 if (v[strlen(v)-1] == '\'') v[strlen(v)-1] = '\0';
511
512 num_options = cupsAddOption(optname, v, num_options, &options);
513 }
514 else if (ropt == EOF)
515 break;
516 }
517 fclose(stream);
518 g_unlink(tmpfile);
519 }
520 else
521 {
522 dt_control_log(_("printing on `%s' cancelled"), pinfo->printer.name);
523 dt_print(DT_DEBUG_PRINT, "[print] command fails with %d, cancel printing\n", exit_status);
524 return;
525 }
526 }
527 else
528 {
529 cups_dest_t *dests;
530 const int num_dests = cupsGetDests(&dests);
531 cups_dest_t *dest = cupsGetDest(pinfo->printer.name, NULL, num_dests, dests);
532
533 for (int j = 0; j < dest->num_options; j ++)
534 if (cupsGetOption(dest->options[j].name, num_options,
535 options) == NULL)
536 num_options = cupsAddOption(dest->options[j].name,
537 dest->options[j].value,
538 num_options, &options);
539
540 cupsFreeDests(num_dests, dests);
541
542 // if we have a profile, disable cm on CUPS, this is important as dt does the cm
543
544 num_options = cupsAddOption("cm-calibration", *pinfo->printer.profile ? "true" : "false", num_options, &options);
545
546 // media to print on
547
548 num_options = cupsAddOption("media", pinfo->paper.name, num_options, &options);
549
550 // the media type to print on
551
552 num_options = cupsAddOption("MediaType", pinfo->medium.name, num_options, &options);
553
554 // never print two-side
555
556 num_options = cupsAddOption("sides", "one-sided", num_options, &options);
557
558 // and a single image per page
559
560 num_options = cupsAddOption("number-up", "1", num_options, &options);
561
562 // if the printer has no hardware margins activate the borderless mode
563
564 if (pinfo->printer.hw_margin_top == 0 || pinfo->printer.hw_margin_bottom == 0
565 || pinfo->printer.hw_margin_left == 0 || pinfo->printer.hw_margin_right == 0)
566 {
567 // there is many variant for this parameter
568 num_options = cupsAddOption("StpFullBleed", "true", num_options, &options);
569 num_options = cupsAddOption("STP_FullBleed", "true", num_options, &options);
570 num_options = cupsAddOption("Borderless", "true", num_options, &options);
571 }
572
573 // as cups-filter pdftopdf will autorotate the page, there is no
574 // need to set an option in the case of landscape mode images
575 }
576
577 // print lp options
578
579 dt_print(DT_DEBUG_PRINT, "[print] printer options (%d)\n", num_options);
580 for (int k=0; k<num_options; k++)
581 dt_print(DT_DEBUG_PRINT, "[print] %2d %s=%s\n", k+1, options[k].name, options[k].value);
582
583 const int job_id = cupsPrintFile(pinfo->printer.name, filename, job_title, num_options, options);
584
585 if (job_id == 0)
586 dt_control_log(_("error while printing `%s' on `%s'"), job_title, pinfo->printer.name);
587 else
588 dt_control_log(_("printing `%s' on `%s'"), job_title, pinfo->printer.name);
589
590 cupsFreeOptions (num_options, options);
591}
592
594 const int32_t area_width, const int32_t area_height,
595 float *px, float *py, float *pwidth, float *pheight,
596 float *ax, float *ay, float *awidth, float *aheight,
597 gboolean *borderless)
598{
599 /* this is where the layout is done for the display and for the print too. So this routine is one
600 of the most critical for the print circuitry. */
601
602 // page w/h
603 float pg_width = prt->paper.width;
604 float pg_height = prt->paper.height;
605
606 /* here, width and height correspond to the area for the picture */
607
608 // non-printable
609 float np_top = prt->printer.hw_margin_top;
610 float np_left = prt->printer.hw_margin_left;
611 float np_right = prt->printer.hw_margin_right;
612 float np_bottom = prt->printer.hw_margin_bottom;
613
614 /* do some arrangements for the landscape mode. */
615
616 if(prt->page.landscape)
617 {
618 float tmp = pg_width;
619 pg_width = pg_height;
620 pg_height = tmp;
621
622 // rotate the non-printable margins
623 tmp = np_top;
624 np_top = np_right;
625 np_right = np_bottom;
626 np_bottom = np_left;
627 np_left = tmp;
628 }
629
630 // the image area aspect
631 const float a_aspect = (float)area_width / (float)area_height;
632
633 // page aspect
634 const float pg_aspect = pg_width / pg_height;
635
636 // display page
637 float p_bottom, p_right;
638
639 if(a_aspect > pg_aspect)
640 {
641 *px = (area_width - (area_height * pg_aspect)) / 2.0f;
642 *py = 0;
643 p_bottom = area_height;
644 p_right = area_width - *px;
645 }
646 else
647 {
648 *px = 0;
649 *py = (area_height - (area_width / pg_aspect)) / 2.0f;
650 p_right = area_width;
651 p_bottom = area_height - *py;
652 }
653
654 *pwidth = p_right - *px;
655 *pheight = p_bottom - *py;
656
657 // page margins, note that we do not want to change those values for the landscape mode.
658 // these margins are those set by the user from the GUI, and the top margin is *always*
659 // at the top of the screen.
660
661 const float border_top = prt->page.margin_top;
662 const float border_left = prt->page.margin_left;
663 const float border_right = prt->page.margin_right;
664 const float border_bottom = prt->page.margin_bottom;
665
666 // display picture area, that is removing the non printable areas and user's margins
667
668 const float bx = *px + (border_left / pg_width) * (*pwidth);
669 const float by = *py + (border_top / pg_height) * (*pheight);
670 const float bb = p_bottom - (border_bottom / pg_height) * (*pheight);
671 const float br = p_right - (border_right / pg_width) * (*pwidth);
672
673 *borderless = border_left < np_left
674 || border_right < np_right
675 || border_top < np_top
676 || border_bottom < np_bottom;
677
678 // now we have the printable area (ax, ay) -> (ax + awidth, ay + aheight)
679
680 *ax = bx;
681 *ay = by;
682 *awidth = br - bx;
683 *aheight = bb - by;
684}
685
686// clang-format off
687// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
688// vim: shiftwidth=2 expandtab tabstop=2 cindent
689// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
690// clang-format on
691
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
#define m
Definition basecurve.c:283
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static const float x
const float l2
const float l1
const float v
void dt_control_log(const char *msg,...)
Definition control.c:824
struct dt_control_t * dt_control_get_global(void)
Definition darktable.c:651
static gint sort_papers(gconstpointer p1, gconstpointer p2)
Definition cups_print.c:264
void dt_get_printer_info(const char *printer_name, dt_printer_info_t *pinfo)
Definition cups_print.c:89
static gboolean paper_exists(GList *papers, const char *name)
Definition cups_print.c:233
void dt_print_file(const int32_t imgid, const char *filename, const char *job_title, const dt_print_info_t *pinfo)
Definition cups_print.c:428
static int _dest_cb(void *user_data, unsigned flags, cups_dest_t *dest)
Definition cups_print.c:162
dt_medium_info_t * dt_get_medium(GList *media, const char *name)
Definition cups_print.c:412
static int _detect_printers_callback(dt_job_t *job)
Definition cups_print.c:184
GList * dt_get_media_type(const dt_printer_info_t *printer)
Definition cups_print.c:375
void dt_printers_discovery(void(*cb)(dt_printer_info_t *pr, void *user_data), void *user_data)
Definition cups_print.c:217
void dt_printers_abort_discovery(void)
Definition cups_print.c:212
void dt_get_print_layout(const dt_print_info_t *prt, const int32_t area_width, const int32_t area_height, float *px, float *py, float *pwidth, float *pheight, float *ax, float *ay, float *awidth, float *aheight, gboolean *borderless)
Definition cups_print.c:593
static int _cancel
Definition cups_print.c:182
dt_paper_info_t * dt_get_paper(GList *papers, const char *name)
Definition cups_print.c:247
GList * dt_get_papers(const dt_printer_info_t *printer)
Definition cups_print.c:273
void dt_init_print_info(dt_print_info_t *pinfo)
Definition cups_print.c:79
#define MAX_NAME
Definition cups_print.h:29
const int res
Definition dtpthread.h:351
void dt_loc_get_tmp_dir(char *tmpdir, size_t bufsize)
dt_job_t * dt_control_job_create(dt_job_execute_callback execute, const char *msg,...)
Definition jobs.c:137
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job)
Definition jobs.c:407
void * dt_control_job_get_params(const _dt_job_t *job)
Definition jobs.c:131
void dt_control_job_set_params(_dt_job_t *job, void *params, dt_job_destroy_callback callback)
Definition jobs.c:114
@ DT_JOB_QUEUE_SYSTEM_BG
Definition jobs.h:58
@ DT_DEBUG_PRINT
Definition logging.h:65
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
#define dt_pdf_point_to_mm(pt)
Definition pdf.h:43
const char * name
Definition pdf.h:90
@ DT_INTENT_PERCEPTUAL
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
Definition simd.h:55
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
char common_name[128]
Definition cups_print.h:51
char name[128]
Definition cups_print.h:51
double margin_bottom
Definition cups_print.h:57
double margin_right
Definition cups_print.h:57
double margin_left
Definition cups_print.h:57
double margin_top
Definition cups_print.h:57
gboolean landscape
Definition cups_print.h:56
char name[128]
Definition cups_print.h:45
char common_name[128]
Definition cups_print.h:45
dt_medium_info_t medium
Definition cups_print.h:75
dt_paper_info_t paper
Definition cups_print.h:74
dt_printer_info_t printer
Definition cups_print.h:72
dt_page_setup_t page
Definition cups_print.h:73
dt_iop_color_intent_t intent
Definition cups_print.h:65
double hw_margin_right
Definition cups_print.h:64
char profile[256]
Definition cups_print.h:66
gboolean is_turboprint
Definition cups_print.h:67
double hw_margin_left
Definition cups_print.h:64
double hw_margin_bottom
Definition cups_print.h:64
void * user_data
Definition cups_print.c:75
void(* cb)(dt_printer_info_t *, void *)
Definition cups_print.c:74
typedef double((*spd)(unsigned long int wavelength, double TempK))
void dt_util_str_to_loc_numbers_format(char *data)
Definition utility.c:825