1 /*
2 *
3 * Super simple color calibration program for the Common UNIX
4 * Printing System.
5 *
6 * Copyright 1993-2000 by Easy Software Products.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 *
21 * Contents:
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <math.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35
36 /*
37 * min/max/abs macros...
38 */
39
40 #ifndef max
41 # define max(a,b) ((a) > (b) ? (a) : (b))
42 #endif /* !max */
43 #ifndef min
44 # define min(a,b) ((a) < (b) ? (a) : (b))
45 #endif /* !min */
46 #ifndef abs
47 # define abs(a) ((a) < 0 ? -(a) : (a))
48 #endif /* !abs */
49
50
51 /*
52 * Prototypes...
53 */
54
55 float get_calibration(const char *prompt, float minval, float maxval);
56 char *safe_gets(const char *prompt, char *s, int size);
57 int safe_geti(const char *prompt, int defval);
58 void send_prolog(FILE *fp);
59 void send_pass1(FILE *fp);
60 void send_pass2(FILE *fp, float kd, float rd, float yellow);
61 void send_pass3(FILE *fp, float kd, float rd, float g, float yellow);
62 void send_pass4(FILE *fp, float red, float green, float blue, const char *p);
63
64
65 /*
66 * 'main()' - Main entry for calibration program.
67 */
68
69 int
main(int argc,char * argv[])70 main(int argc,
71 char *argv[])
72 {
73 char printer[255];
74 char resolution[255];
75 char mediatype[255];
76 char *profile;
77 char cupsProfile[1024];
78 char command[1024];
79 char lpoptionscommand[1024];
80 char line[255];
81 char junk[255];
82 FILE *fp;
83 float kd, rd, g;
84 float color;
85 float red, green, blue;
86 float cyan, magenta, yellow;
87 float m[3][3];
88
89
90 puts("ESP Printer Calibration Tool v1.0");
91 puts("Copyright 1999-2000 by Easy Software Products, All Rights Reserved.");
92 puts("");
93 puts("This program allows you to calibrate the color output of printers");
94 puts("using the Gutenprint CUPS or ESP Print Pro drivers.");
95 puts("");
96 puts("Please note that this program ONLY works with the Gutenprint CUPS");
97 puts("driver.");
98 puts("");
99 puts("These drivers by the text \"CUPS+Gutenprint\"");
100 puts("the model description displayed by the CUPS web interface or");
101 puts("similar tool.");
102 puts("");
103 puts("If you are not using the correct driver, press CTRL+C now and");
104 puts("reinstall your printer queue with the appropriate driver first.");
105 puts("");
106 puts("To make a calibration profile for all users, run this program as");
107 puts("the \"root\" user.");
108 puts("");
109 puts("");
110
111 safe_gets("Printer name [default]?", printer, sizeof(printer));
112 safe_gets("Resolution [default]?", resolution, sizeof(resolution));
113 safe_gets("Media type [default]?", mediatype, sizeof(mediatype));
114
115 strcpy(command, "lp -s");
116 if (printer[0])
117 {
118 strcat(command, " -d ");
119 strcat(command, printer);
120 }
121 if (resolution[0])
122 {
123 strcat(command, " -o resolution=");
124 strcat(command, resolution);
125 }
126 if (mediatype[0])
127 {
128 strcat(command, " -o media=");
129 strcat(command, mediatype);
130 }
131
132 strcat(command, " -o profile=");
133
134 profile = command + strlen(command);
135
136 strcpy(profile, "1000,1000,1000,0,0,0,1000,0,0,0,1000");
137
138 safe_gets("Press ENTER to print pass #1 or N to skip...", junk, sizeof(junk));
139
140 if (!junk[0])
141 {
142 puts("Sending calibration pass #1 for density/saturation levels...");
143
144 fp = popen(command, "w");
145 send_prolog(fp);
146 send_pass1(fp);
147 fputs("showpage\n", fp);
148 pclose(fp);
149
150 puts("Calibration pass #1 sent.");
151 }
152
153 puts("");
154 puts("Please select the character that corresponds to the black block that");
155 puts("is 100% saturated (dark) while not bleeding through the paper. If");
156 puts("the saturation point appears to occur between two characters, enter");
157 puts("both characters.");
158 puts("");
159
160 kd = get_calibration("Black density?", 0.25f, 1.0f);
161
162 puts("");
163 puts("Now select the character that corresponds to the yellow block that is");
164 puts("100% saturated (dark) while not bleeding through the paper. If the");
165 puts("saturation point appears to occur between two characters, enter both");
166 puts("characters.");
167 puts("");
168
169 cyan = kd;
170 magenta = kd;
171 yellow = get_calibration("Yellow density?", 0.25f, 1.0f);
172
173 puts("");
174 puts("Now select the character that corresponds to the red block that is");
175 puts("100% saturated (dark) while not bleeding through the paper. If the");
176 puts("saturation point appears to occur between two characters, enter both");
177 puts("characters.");
178 puts("");
179
180 rd = get_calibration("Red density?", 0.5f, 2.0f);
181
182 puts("");
183 puts("Thank you. Now insert the page back into the printer and press the");
184 puts("ENTER key to print calibration pass #2.");
185 puts("");
186
187 safe_gets("Press ENTER to print pass #2 or N to skip...", junk, sizeof(junk));
188
189 if (!junk[0])
190 {
191 puts("Sending calibration pass #2 for gamma levels...");
192
193 fp = popen(command, "w");
194 send_prolog(fp);
195 send_pass2(fp, kd, rd, yellow);
196 fputs("showpage\n", fp);
197 pclose(fp);
198
199 puts("Calibration pass #2 sent.");
200 }
201
202 puts("");
203 puts("Please select the character that corresponds to the column of gray");
204 puts("blocks that appear to be 1/2 and 1/4 as dark as the black blocks,");
205 puts("respectively. If the transition point appears to occur between two");
206 puts("characters, enter both characters.");
207 puts("");
208
209 g = get_calibration("Gamma?", 1.0f, 4.0f);
210
211 puts("");
212 puts("Thank you. Now insert the page back into the printer and press the");
213 puts("ENTER key to print calibration pass #3.");
214 puts("");
215
216 safe_gets("Press ENTER to print pass #3 or N to skip...", junk, sizeof(junk));
217
218 if (!junk[0])
219 {
220 puts("Sending calibration pass #3 for red, green, and blue adjustment...");
221
222 fp = popen(command, "w");
223 send_prolog(fp);
224 send_pass3(fp, kd, rd, g, yellow);
225 fputs("showpage\n", fp);
226 pclose(fp);
227
228 puts("Calibration pass #3 sent.");
229 }
230
231 puts("");
232 puts("Please select the character that corresponds to the correct red,");
233 puts("green, and blue colors. If the transition point appears to occur");
234 puts("between two characters, enter both characters.");
235 puts("");
236
237 red = get_calibration("Red color?", 0.35f, -0.40f);
238 green = get_calibration("Green color?", 0.35f, -0.40f);
239 blue = get_calibration("Blue color?", 0.35f, -0.40f);
240
241 color = 0.5f * rd / kd - kd;
242
243 cyan /= kd;
244 magenta /= kd;
245 yellow /= kd;
246
247 m[0][0] = cyan; /* C */
248 m[0][1] = cyan * (color + blue); /* C + M (blue) */
249 m[0][2] = cyan * (color - green); /* C + Y (green) */
250 m[1][0] = magenta * (color - blue); /* M + C (blue) */
251 m[1][1] = magenta; /* M */
252 m[1][2] = magenta * (color + red); /* M + Y (red) */
253 m[2][0] = yellow * (color + green); /* Y + C (green) */
254 m[2][1] = yellow * (color - red); /* Y + M (red) */
255 m[2][2] = yellow; /* Y */
256
257 if (m[0][1] > 0.0f)
258 {
259 m[1][0] -= m[0][1];
260 m[0][1] = 0.0f;
261 }
262 else if (m[1][0] > 0.0f)
263 {
264 m[0][1] -= m[1][0];
265 m[1][0] = 0.0f;
266 }
267
268 if (m[0][2] > 0.0f)
269 {
270 m[2][0] -= m[0][2];
271 m[0][2] = 0.0f;
272 }
273 else if (m[2][0] > 0.0f)
274 {
275 m[0][2] -= m[2][0];
276 m[2][0] = 0.0f;
277 }
278
279 if (m[1][2] > 0.0f)
280 {
281 m[2][1] -= m[1][2];
282 m[1][2] = 0.0f;
283 }
284 else if (m[2][1] > 0.0f)
285 {
286 m[1][2] -= m[2][1];
287 m[2][1] = 0.0f;
288 }
289
290 sprintf(profile, "%.0f,%.0f,%.0f,%.0f,%.0f,%.0f,%.0f,%.0f,%.0f,%.0f,%.0f",
291 kd * 1000.0f, g * 1000.0f,
292 m[0][0] * 1000.0f, m[0][1] * 1000.0f, m[0][2] * 1000.0f,
293 m[1][0] * 1000.0f, m[1][1] * 1000.0f, m[1][2] * 1000.0f,
294 m[2][0] * 1000.0f, m[2][1] * 1000.0f, m[2][2] * 1000.0f);
295
296 sprintf(cupsProfile, " *cupsColorProfile %s/%s: \"%.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\"\n",
297 resolution[0] ? resolution : "-", mediatype[0] ? mediatype : "-",
298 kd, g, m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2],
299 m[2][0], m[2][1], m[2][2]);
300
301 puts("");
302 puts("Thank you. Now insert the page back into the printer and press the");
303 puts("ENTER key to print the final calibration pass.");
304 puts("");
305
306 safe_gets("Press ENTER to continue...", junk, sizeof(junk));
307
308 puts("Sending calibration pass #4 for visual confirmation...");
309
310 fp = popen(command, "w");
311 send_prolog(fp);
312 send_pass4(fp, red, green, blue, cupsProfile);
313 fputs("showpage\n", fp);
314 pclose(fp);
315
316 puts("Calibration pass #4 sent.");
317
318 puts("");
319 puts("The basic color profile for these values is:");
320 puts("");
321 printf(" %s\n", cupsProfile);
322 puts("");
323 puts("You can add this to the PPD file for this printer to make this change");
324 puts("permanent, or use the following option with a printing command:");
325 puts("");
326 printf(" -o profile=%s\n", profile);
327 puts("");
328 puts("to use the profile for this job only.");
329 puts("");
330 puts("Calibration is complete.");
331 puts("");
332
333 if (getuid() == 0)
334 {
335 do
336 safe_gets("Would you like to save the profile as a system-wide default (y/n)? ",
337 line, sizeof(line));
338 while (tolower(line[0]) != 'n' && tolower(line[0]) != 'y');
339 }
340 else
341 line[0] = 'n';
342
343 if (line[0] == 'n')
344 {
345 do
346 safe_gets("Would you like to save the profile as a personal default (y/n)? ",
347 line, sizeof(line));
348 while (tolower(line[0]) != 'n' && tolower(line[0]) != 'y');
349 }
350
351 puts("");
352 if (tolower(line[0]) == 'n')
353 {
354 puts("Calibration profile NOT saved.");
355 return (0);
356 }
357
358 strcpy(lpoptionscommand, "lpoptions");
359 if (printer[0])
360 {
361 strcat(lpoptionscommand, " -p ");
362 strcat(lpoptionscommand, printer);
363 }
364
365 strcat(lpoptionscommand, " -o profile=");
366
367 strcat(lpoptionscommand, profile);
368
369 if (system(lpoptionscommand) == 0)
370 puts("Calibration profile successfully saved.");
371 else
372 puts("An error occurred while saving the calibration profile.");
373
374 return (0);
375 }
376
377
378 float
get_calibration(const char * prompt,float minval,float maxval)379 get_calibration(const char *prompt,
380 float minval,
381 float maxval)
382 {
383 char line[4]; /* Input from user */
384 int val1, val2; /* Calibration values */
385
386
387 do
388 {
389 if (safe_gets(prompt, line, sizeof(line)) == NULL)
390 return (minval);
391 }
392 while (!isxdigit(line[0]) || (line[1] && !isxdigit(line[1])));
393
394 if (isdigit(line[0]))
395 val1 = line[0] - '0';
396 else
397 val1 = tolower(line[0]) - 'a' + 10;
398
399 if (!line[1])
400 val2 = val1;
401 else if (isdigit(line[1]))
402 val2 = line[1] - '0';
403 else
404 val2 = tolower(line[1]) - 'a' + 10;
405
406 return (minval + (maxval - minval) * (val1 + val2) / 30.0f);
407 }
408
409
410 int
safe_geti(const char * prompt,int defval)411 safe_geti(const char *prompt,
412 int defval)
413 {
414 char line[255];
415
416
417 do
418 {
419 safe_gets(prompt, line, sizeof(line));
420
421 if (defval && !line[0])
422 return (defval);
423 }
424 while (!line[0] || !isdigit(line[0]));
425
426 return (atoi(line));
427 }
428
429
430 /*
431 * 'safe_gets()' - Get a string from the user.
432 */
433
434 char *
safe_gets(const char * prompt,char * s,int size)435 safe_gets(const char *prompt,
436 char *s,
437 int size)
438 {
439 printf("%s ", prompt);
440
441 if (fgets(s, size, stdin) == NULL)
442 return (NULL);
443
444 if (s[0])
445 s[strlen(s) - 1] = '\0';
446
447 return (s);
448 }
449
450
451 void
send_prolog(FILE * fp)452 send_prolog(FILE *fp)
453 {
454 fputs("%!\n", fp);
455 fputs("/Helvetica findfont 12 scalefont setfont\n", fp);
456 fputs("/BLOCK {\n"
457 " 14.4 mul neg 720 add exch\n"
458 " 14.4 mul 72 add exch\n"
459 " 14.4 14.4 rectfill\n"
460 "} bind def\n", fp);
461 fputs("/DIAMOND {\n"
462 " 14.4 mul neg 720 add 7.2 add exch\n"
463 " 14.4 mul 72 add exch\n"
464 " newpath\n"
465 " moveto\n"
466 " 7.2 7.2 rlineto\n"
467 " 7.2 -7.2 rlineto\n"
468 " -7.2 -7.2 rlineto\n"
469 " closepath\n"
470 " 0 ne { fill } { stroke } ifelse\n"
471 "} bind def\n", fp);
472 fputs("/PLUS {\n"
473 " 14.4 mul neg 720 add 7.2 add exch\n"
474 " 14.4 mul 72 add exch\n"
475 " newpath\n"
476 " moveto\n"
477 " 14.4 0 rlineto\n"
478 " -7.2 -7.2 rmoveto\n"
479 " 0 14.4 rlineto\n"
480 " closepath\n"
481 " fill\n"
482 "} bind def\n", fp);
483 fputs("/TEXT {\n"
484 " 14.4 mul neg 720 add 4 add exch\n"
485 " 14.4 mul 72 add 7.2 add exch\n"
486 " moveto\n"
487 " dup stringwidth pop 0.5 mul neg 0 rmoveto\n"
488 " show\n"
489 "} bind def\n", fp);
490 }
491
492
493 void
send_pass1(FILE * fp)494 send_pass1(FILE *fp)
495 {
496 int i;
497 float p;
498 static const char *hex = "FEDCBA9876543210";
499
500
501 fputs("0 setgray", fp);
502 fputs("(K) 0 1 TEXT\n", fp);
503 fputs("(Y) 0 2 TEXT\n", fp);
504 fputs("(R) 0 4 TEXT\n", fp);
505
506 for (i = 0; i < 16; i ++)
507 {
508 fprintf(fp, "(%d) %d 0 TEXT\n", 100 - i * 5, i * 2 + 2);
509 fprintf(fp, "(%c) %d 3 TEXT\n", hex[i], i * 2 + 2);
510 fprintf(fp, "(%d) %d 5 TEXT\n", 200 - i * 10, i * 2 + 2);
511 }
512
513 for (i = 0; i < 16; i ++)
514 {
515 p = 0.01f * (100 - i * 5);
516
517 fprintf(fp, "%.2f setgray %d 1 BLOCK\n", 1.0 - p, i * 2 + 2);
518 fprintf(fp, "0 0 %.2f 0 setcmykcolor %d 2 BLOCK\n", p, i * 2 + 2);
519 fprintf(fp, "0 %.2f %.2f 0 setcmykcolor %d 4 BLOCK\n", p, p, i * 2 + 2);
520 }
521 }
522
523
524 void
send_pass2(FILE * fp,float kd,float rd,float yellow)525 send_pass2(FILE *fp,
526 float kd,
527 float rd,
528 float yellow)
529 {
530 int i;
531 float p;
532 float g;
533 static const char *hex = "FEDCBA9876543210";
534
535
536 rd *= 0.5f;
537
538 fprintf(fp, "0 0 %.2f 0 setcmykcolor\n", yellow);
539 fprintf(fp, "1 %.2f 6 DIAMOND\n", 2.0f + 30.0f * (1.0f - yellow) / 0.75f);
540
541 fprintf(fp, "0 %.2f %.2f 0 setcmykcolor\n", rd, rd);
542 fprintf(fp, "%d %.2f 6 DIAMOND\n", rd != yellow,
543 2.0f + 30.0f * (1.0f - rd) / 0.75f);
544
545 p = 1.0f - kd;
546 fprintf(fp, "%.2f setgray\n", p);
547
548 if (kd == rd && kd == yellow)
549 fprintf(fp, "%.2f 6 PLUS\n", 2.0f + 30.0f * (1.0f - kd) / 0.75f);
550 else
551 fprintf(fp, "%d %.2f 6 DIAMOND\n", kd != yellow && kd != rd,
552 2.0f + 30.0f * (1.0f - kd) / 0.75f);
553
554 fputs("(100%) 0 9 TEXT\n", fp);
555 fputs("(50%) 0 10 TEXT\n", fp);
556 fputs("(25%) 0 11 TEXT\n", fp);
557
558 for (i = 0; i < 16; i ++)
559 {
560 fprintf(fp, "(%.1f) %d 8 TEXT\n", 0.2f * (20 - i), i * 2 + 2);
561 fprintf(fp, "(%c) %d 12 TEXT\n", hex[i], i * 2 + 2);
562 }
563
564 for (i = 0; i < 16; i ++)
565 {
566 g = 0.2f * (20 - i);
567
568 p = 1.0f - kd * (float)pow(1.0f, g);
569 fprintf(fp, "%.2f setgray %d 9 BLOCK\n", p, i * 2 + 2);
570
571 p = 1.0f - kd * (float)pow(0.5f, g);
572 fprintf(fp, "%.2f setgray %d 10 BLOCK\n", p, i * 2 + 2);
573
574 p = 1.0f - kd * (float)pow(0.25f, g);
575 fprintf(fp, "%.2f setgray %d 11 BLOCK\n", p, i * 2 + 2);
576 }
577 }
578
579
580 void
send_pass3(FILE * fp,float kd,float rd,float g,float yellow)581 send_pass3(FILE *fp,
582 float kd,
583 float rd,
584 float g,
585 float yellow)
586 {
587 int i;
588 float p;
589 float color;
590 float c, m, y;
591 float adj;
592 static const char *hex = "FEDCBA9876543210";
593
594
595 p = 1.0f - kd;
596 fprintf(fp, "%.2f setgray\n", p);
597 fprintf(fp, "1 %.2f 13 DIAMOND\n", 2.0f + 30.0f * (4.0f - g) / 3.0f);
598
599 color = 0.5f * rd / kd - kd;
600 yellow /= kd;
601
602 fputs("(R) 2 16 TEXT\n", fp);
603 fputs("(G) 2 17 TEXT\n", fp);
604 fputs("(B) 2 18 TEXT\n", fp);
605
606 for (i = 1; i < 16; i ++)
607 {
608 fprintf(fp, "(%+d) %d 15 TEXT\n", i * 5 - 40, i * 2 + 2);
609 fprintf(fp, "(%c) %d 19 TEXT\n", hex[i], i * 2 + 2);
610 }
611
612 for (i = 1; i < 16; i ++)
613 {
614 /* Adjustment value */
615 adj = i * 0.05f - 0.40f;
616
617 /* RED */
618 c = 0.0f;
619 m = color + adj;
620 y = color - adj;
621 if (m > 0)
622 {
623 y -= m;
624 m = 0;
625 }
626 else if (y > 0)
627 {
628 m -= y;
629 y = 0;
630 }
631
632 m += 1.0f;
633 y = yellow * (1.0f + y);
634
635 if (c <= 0.0f)
636 c = 0.0f;
637 else if (c >= 1.0f)
638 c = 1.0f;
639 else
640 c = (float)pow(c, g);
641
642 if (m <= 0.0f)
643 m = 0.0f;
644 else if (m >= 1.0f)
645 m = 1.0f;
646 else
647 m = (float)pow(m, g);
648
649 if (y <= 0.0f)
650 y = 0.0f;
651 else if (y >= 1.0f)
652 y = 1.0f;
653 else
654 y = (float)pow(y, g);
655
656 fprintf(fp, "%.2f %.2f %.2f 0 setcmykcolor %d 16 BLOCK\n",
657 c * kd, m * kd, y * kd, i * 2 + 2);
658
659 /* GREEN */
660 c = color - adj;
661 m = 0.0f;
662 y = color + adj;
663
664 if (c > 0)
665 {
666 y -= c;
667 c = 0;
668 }
669 else if (y > 0)
670 {
671 c -= y;
672 y = 0;
673 }
674
675 c += 1.0f;
676 y = yellow * (1.0f + y);
677
678 if (c <= 0.0f)
679 c = 0.0f;
680 else if (c >= 1.0f)
681 c = 1.0f;
682 else
683 c = (float)pow(c, g);
684
685 if (m <= 0.0f)
686 m = 0.0f;
687 else if (m >= 1.0f)
688 m = 1.0f;
689 else
690 m = (float)pow(m, g);
691
692 if (y <= 0.0f)
693 y = 0.0f;
694 else if (y >= 1.0f)
695 y = 1.0f;
696 else
697 y = (float)pow(y, g);
698
699 fprintf(fp, "%.2f %.2f %.2f 0 setcmykcolor %d 17 BLOCK\n",
700 c * kd, m * kd, y * kd, i * 2 + 2);
701
702 /* BLUE */
703 c = color + adj;
704 m = color - adj;
705 y = 0.0f;
706
707 if (c > 0)
708 {
709 m -= c;
710 c = 0;
711 }
712 else if (m > 0)
713 {
714 c -= m;
715 m = 0;
716 }
717
718 c += 1.0f;
719 m += 1.0f;
720
721 if (c <= 0.0f)
722 c = 0.0f;
723 else if (c >= 1.0f)
724 c = 1.0f;
725 else
726 c = (float)pow(c, g);
727
728 if (m <= 0.0f)
729 m = 0.0f;
730 else if (m >= 1.0f)
731 m = 1.0f;
732 else
733 m = (float)pow(m, g);
734
735 if (y <= 0.0f)
736 y = 0.0f;
737 else if (y >= 1.0f)
738 y = 1.0f;
739 else
740 y = (float)pow(y, g);
741
742 fprintf(fp, "%.2f %.2f %.2f 0 setcmykcolor %d 18 BLOCK\n",
743 c * kd, m * kd, y * kd, i * 2 + 2);
744 }
745 }
746
747
748 void
send_pass4(FILE * fp,float red,float green,float blue,const char * profile)749 send_pass4(FILE *fp,
750 float red,
751 float green,
752 float blue,
753 const char *profile)
754 {
755 FILE *ppm;
756 int x, y, col, width, height;
757 int r, g, b;
758 char line[255];
759
760
761 fprintf(fp, "0 0 1 setrgbcolor 1 %.2f 20 DIAMOND\n", /* BLUE */
762 2.0f + 30.0f * (0.40f + blue) / 0.75f);
763 fprintf(fp, "1 0 0 setrgbcolor %d %.2f 20 DIAMOND\n", /* RED */
764 red != blue, 2.0f + 30.0f * (0.40f + red) / 0.75f);
765 if (green == red && green == blue)
766 fprintf(fp, "0 1 0 setrgbcolor %.2f 20 PLUS\n", /* GREEN */
767 2.0f + 30.0f * (0.40f + green) / 0.75f);
768 else
769 fprintf(fp, "0 1 0 setrgbcolor %d %.2f 20 DIAMOND\n", /* GREEN */
770 green != red && green != blue,
771 2.0f + 30.0f * (0.40f + green) / 0.75f);
772
773 fputs("0 setgray\n", fp);
774 fputs("currentfont 0.8 scalefont setfont\n", fp);
775
776 fprintf(fp, "(%s) 16 22 TEXT\n", profile);
777
778 if ((ppm = fopen(CUPS_DATADIR "/calibrate.ppm", "rb")) == NULL)
779 if ((ppm = fopen("calibrate.ppm", "rb")) == NULL)
780 return;
781
782 fgets(line, sizeof(line), ppm);
783 while (fgets(line, sizeof(line), ppm))
784 if (line[0] != '#')
785 break;
786
787 sscanf(line, "%d%d", &width, &height);
788
789 fgets(line, sizeof(line), ppm);
790
791 fputs("gsave\n", fp);
792 fprintf(fp, "72 %d translate\n", 504 * height / width + 72);
793 fprintf(fp, "504 -%d scale\n", 504 * height / width);
794
795 fprintf(fp, "/scanline %d string def\n", width * 3);
796
797 fprintf(fp, "%d %d 8\n", width, height);
798 fprintf(fp, "[%d 0 0 %d 0 0]\n", width, height);
799 fputs("{ currentfile scanline readhexstring pop } false 3 colorimage\n", fp);
800
801 for (y = 0, col = 0; y < height; y ++)
802 {
803 printf("Sending scanline %d of %d...\r", y + 1, height);
804 fflush(stdout);
805
806 for (x = 0; x < width; x ++)
807 {
808 r = getc(ppm);
809 g = getc(ppm);
810 b = getc(ppm);
811
812 fprintf(fp, "%02X%02X%02X", r, g, b);
813 col ++;
814 if (col >= 12)
815 {
816 col = 0;
817 putc('\n', fp);
818 }
819 }
820 }
821
822 if (col)
823 putc('\n', fp);
824
825 printf(" \r");
826
827 fclose(ppm);
828
829 fputs("grestore\n", fp);
830 }
831