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