ui: initialize alignment display parameters, so that these do not assume
[Ale.git] / d2 / tfile.h
blobd38c9de2daadec2719e0d5804fff5bcb5c910ed9
1 // Copyright 2002, 2003, 2007 David Hilvert <dhilvert@auricle.dyndns.org>,
2 // <dhilvert@ugcs.caltech.edu>
4 /* This file is part of the Anti-Lamenessing Engine.
6 The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * tfile.h: Read and write transformation data files.
26 * This version of ALE reads transformation data file versions 0, 1, 2, and 3,
27 * and writes version 2 and 3 transformation data files. Data file versions 1
28 * and higher are identified by a version command "V x", where x is the version
29 * number, prior to any transformation command. Data file version 0 is
30 * identified by having no version command.
33 #ifndef __tfile_h__
34 #define __tfile_h__
36 #include "transformation.h"
38 #define TFILE_VERSION 3
39 #define TFILE_VERSION_MAX 3
41 extern int tfile_input_version;
42 extern int tfile_output_version;
45 * Structure to describe a transformation data file to load data from.
48 struct tload_t {
49 const char *filename;
50 FILE *file;
54 * Structure to describe a transformation data file to write data to.
57 struct tsave_t {
58 const char *filename;
59 const char *target;
60 const char *orig;
61 FILE *file;
65 * Create a new tload_t transformation data file structure, used for
66 * reading data from transformation data files.
69 static inline struct tload_t *tload_new(const char *filename) {
70 FILE *file = fopen (filename, "r");
71 struct tload_t *result = NULL;
73 if (!file) {
74 fprintf(stderr, "tload: Error: could not open transformation data file '%s'.", filename);
75 exit(1);
78 result = (struct tload_t *)
79 malloc(sizeof(struct tload_t));
80 result->filename = filename;
81 result->file = file;
83 return result;
87 * Load the first transformation from a transformation data file associated with
88 * transformation data file structure T, or return the default transformation
89 * if no transformation is available.
91 * T is a pointer to the tload_t transformation data file structure.
93 * IS_P is nonzero if a projective transformation is expected.
95 * DEFAULT_TRANSFORM is the default transformation result.
97 * IS_DEFAULT is used to signal a non-default transformation result.
100 static inline transformation tload_first(struct tload_t *t, int is_p,
101 transformation default_transform, int *is_default) {
103 transformation result = default_transform;
105 *is_default = 1;
108 * If there is no file, return the default.
111 if (t == NULL)
112 return result;
115 * Search through the initial part of the file to determine
116 * its version.
120 * Skip comments
123 int first_character;
125 first_character = fgetc(t->file);
127 while (first_character == ' '
128 || first_character == 0xa
129 || first_character == 0xd
130 || first_character == '\t'
131 || first_character == '#') {
132 ungetc(first_character, t->file);
133 char line[1024];
134 fgets(line, 1024, t->file);
135 if (strlen(line) >= 1023) {
136 fprintf(stderr,
137 "\ntrans-load: Error: line too long in input file\n");
138 exit(1);
141 first_character = fgetc(t->file);
144 if (first_character != EOF)
145 ungetc(first_character, t->file);
148 * Check for version 0
151 if (first_character != 'V')
154 * Must be version 0.
157 return result;
160 * Obtain version from version command string.
163 char line[1024];
164 fgets(line, 1024, t->file);
165 if (strlen(line) >= 1023) {
166 fprintf(stderr,
167 "\ntrans-load: Error: line too long in input file\n");
168 exit(1);
171 int count = sscanf(line, "V %d", &tfile_input_version);
173 if (count < 1) {
174 fprintf(stderr, "Error in transformation "
175 "file version command.\n");
176 exit(1);
177 } else if (tfile_input_version > TFILE_VERSION_MAX) {
178 fprintf(stderr, "Unsupported transformation "
179 "file version %d\n",
180 tfile_input_version);
181 exit(1);
185 * Handle versions lower than 3.
188 if (tfile_input_version < 3)
191 * Versions lower than 3 use the default transformation
192 * for the original frame.
195 return result;
198 * Read each line of the file until we find a transformation
199 * or EOF.
202 while (!feof(t->file)) {
203 char line[1024];
205 fgets(line, 1024, t->file);
207 if (feof(t->file))
208 return result;
210 if (strlen(line) >= 1023) {
211 fprintf(stderr,
212 "\ntrans-load: Error: line too long in input file\n");
213 exit(1);
216 switch (line[0]) {
217 case ' ':
218 case 0xa:
219 case 0xd:
220 case '\t':
221 case '#':
222 /* Comment or whitespace */
223 break;
224 case 'D':
225 case 'd':
226 /* Default transformation */
227 return result;
228 case 'B':
229 case 'b':
230 if (tfile_input_version < 3) {
231 fprintf(stderr, "\ntrans-load: Error: "
232 "Barrel distortion not supported "
233 "for version %d input files.\n"
234 "trans-load: Hint: Use version 3 "
235 "file syntax.\n", tfile_input_version);
236 exit(1);
237 } else {
238 unsigned int count;
239 unsigned int pos = 0, chars;
240 unsigned int bdc;
241 double dparameters[BARREL_DEGREE];
242 ale_pos parameters[BARREL_DEGREE];
244 count = sscanf(line, "B %u%n", &bdc, &chars);
245 pos += chars;
247 if (count < 1) {
248 fprintf(stderr, "\ntrans-load: Error: "
249 "Malformed 'B' command.\n");
250 exit(1);
253 if (bdc > result.bd_max()) {
254 fprintf(stderr, "\ntrans-load: Error: "
255 "Barrel distortion degree %d "
256 "is too large. (Maximum is %d.)\n"
257 "trans-load: Hint: "
258 "Reduce degree or re-compile "
259 "with BD_DEGREE=%d\n", bdc, BARREL_DEGREE, bdc);
260 exit(1);
263 for (unsigned int d = 0; d < bdc; d++) {
264 count = sscanf(line + pos, "%lf%n", &dparameters[d], &chars);
265 pos += chars;
267 if (count < 1) {
268 fprintf(stderr, "\ntrans-load: Error: "
269 "Malformed 'B' command.\n");
270 exit(1);
273 parameters[d] = dparameters[d];
276 result.bd_set(bdc, parameters);
278 break;
279 case 'P':
280 case 'p':
281 /* Projective transformation data */
282 *is_default = 0;
283 if (is_p == 0) {
284 fprintf(stderr, "\ntrans-load: Error: "
285 "Projective data for euclidean "
286 "transformation.\n"
287 "trans-load: Hint: "
288 "Use command-line option --projective.\n");
289 exit(1);
290 } else {
291 double width, height, values[8];
292 int count, i;
293 point x[4];
295 count = sscanf(line + 1, " %lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", &width, &height,
296 &values[0], &values[1], &values[2], &values[3],
297 &values[4], &values[5], &values[6], &values[7]);
299 int index = 0;
300 for (int i = 0; i < 4; i++)
301 for (int j = 1; j >= 0; j--)
302 x[i][j] = values[index++];
304 if (count < 10)
305 fprintf(stderr, "\ntrans-load: warning:"
306 "Missing args for 'P'\n");
308 for (i = 0; i < count - 2; i++) {
309 ale_pos factor = (i % 2)
310 ? ((double) result.scaled_width() / width)
311 : ((double) result.scaled_height() / height);
313 x[i / 2][i % 2] *= factor;
316 result.gpt_set(x);
318 return result;
320 break;
321 case 'E':
322 case 'e':
323 /* Euclidean transformation data */
324 *is_default = 0;
326 double width, height;
327 double values[3] = {0, 0, 0};
328 int count, i;
329 ale_pos eu[3];
331 count = sscanf(line + 1, " %lf%lf%lf%lf%lf",
332 &width, &height,
333 &values[0], &values[1], &values[2]);
335 eu[1] = values[0];
336 eu[0] = values[1];
337 eu[2] = values[2];
339 if (count < 5)
340 fprintf(stderr, "\ntrans-load: warning:"
341 "Missing args for 'E'\n");
343 for (i = 0; (i < count - 2) && (i < 2); i++) {
344 ale_pos factor = (i % 2)
345 ? ((double) result.scaled_width() / width)
346 : ((double) result.scaled_height() / height);
348 eu[i] *= factor;
351 result.eu_set(eu);
353 return result;
355 break;
356 default:
357 fprintf(stderr,
358 "\ntrans-load: Error in tload_first: unrecognized command '%s'\n",
359 line);
360 exit(1);
365 * EOF reached: return default transformation.
368 return result;
372 * Load the next transformation from a transformation data file associated with
373 * transformation data file structure T, or return the default transformation
374 * if no transformation is available.
376 * T is a pointer to the tload_t transformation data file structure.
378 * IS_P is nonzero if a projective transformation is expected.
380 * DEFAULT_TRANSFORM is the default transformation result.
382 * IS_DEFAULT is used to signal a non-default transformation result.
384 * IS_PRIMARY is used to differentiate primary and non-primary
385 * transformations
388 static inline transformation tload_next(struct tload_t *t, int is_p,
389 transformation default_transform, int *is_default,
390 int is_primary) {
392 transformation result = default_transform;
394 *is_default = 1;
397 * Read each line of the file until we find a transformation.
400 while (t && !feof(t->file)) {
402 char c = fgetc(t->file);
403 if (!feof(t->file) && c != EOF)
404 ungetc(c, t->file);
406 if (feof(t->file)
407 || (!is_primary
408 && c != EOF
409 && (c == 'E'
410 || c == 'e'
411 || c == 'P'
412 || c == 'p'
413 || c == 'D'
414 || c == 'd'
415 || c == 'B'
416 || c == 'b'))) {
417 return result;
420 char line[1024];
422 fgets(line, 1024, t->file);
424 if (feof(t->file))
425 return result;
427 if (strlen(line) >= 1023) {
428 fprintf(stderr,
429 "\ntrans-load: warning: line too long in input file\n");
432 switch (line[0]) {
433 case ' ':
434 case 0xa:
435 case 0xd:
436 case '\t':
437 case '#':
438 /* Comment or whitespace */
439 break;
440 case 'D':
441 case 'd':
442 /* Default transformation */
443 return result;
444 case 'B':
445 case 'b':
446 if (tfile_input_version < 3) {
447 fprintf(stderr, "\ntrans-load: Error: "
448 "Barrel distortion not supported "
449 "for version %d input files.\n"
450 "trans-load: Hint: Use version 3 "
451 "file syntax.\n", tfile_input_version);
452 exit(1);
453 } else {
454 unsigned int count;
455 unsigned int pos = 0, chars;
456 unsigned int bdc;
457 ale_pos parameters[BARREL_DEGREE];
458 double dparameters[BARREL_DEGREE];
460 count = sscanf(line, "B %u%n", &bdc, &chars);
461 pos += chars;
463 if (count < 1) {
464 fprintf(stderr, "\ntrans-load: Error: "
465 "Malformed 'B' command.\n");
466 exit(1);
469 if (bdc > result.bd_max()) {
470 fprintf(stderr, "\ntrans-load: Error: "
471 "Barrel distortion degree %d "
472 "is too large. (Maximum is %d.)\n"
473 "trans-load: Hint: "
474 "Reduce degree or re-compile "
475 "with BD_DEGREE=%d\n", bdc, BARREL_DEGREE, bdc);
476 exit(1);
479 for (unsigned int d = 0; d < bdc; d++) {
480 count = sscanf(line + pos, "%lf%n", &dparameters[d], &chars);
481 pos += chars;
483 if (count < 1) {
484 fprintf(stderr, "\ntrans-load: Error: "
485 "Malformed 'B' command.\n");
486 exit(1);
489 parameters[d] = dparameters[d];
492 result.bd_set(bdc, parameters);
494 break;
495 case 'Q':
496 case 'q':
497 if (is_primary)
498 break;
499 case 'P':
500 case 'p':
501 /* Projective transformation data */
502 if (is_p == 0) {
503 fprintf(stderr, "\ntrans-load: Error: "
504 "Projective data for euclidean "
505 "transformation.\n"
506 "trans-load: Hint: "
507 "Use command-line option --projective.\n");
508 exit(1);
509 } else {
510 double width, height, values[8];
511 int count, i;
512 point x[4];
513 transformation::multi_coordinate mc1, mc2;
515 count = sscanf(line + 1, " %lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%d%d%d", &width, &height,
516 &values[0], &values[1], &values[2], &values[3],
517 &values[4], &values[5], &values[6], &values[7],
518 &mc1.degree, &mc1.x, &mc1.y);
520 if (count == 13) {
521 mc2 = default_transform.get_current_coordinate();
523 if (mc1.degree < mc2.degree
524 || (mc1.degree == mc2.degree && mc1.y < mc2.y)
525 || (mc1.degree == mc2.degree && mc1.y == mc2.y && mc1.x < mc2.x))
526 break;
527 if (mc1.degree != mc2.degree
528 || mc1.x != mc2.x
529 || mc1.y != mc2.y) {
530 if (!result.exists(mc1))
531 break;
532 result.set_current_index(result.get_index(mc1));
536 int index = 0;
537 for (int i = 0; i < 4; i++)
538 for (int j = 1; j >= 0; j--)
539 x[i][j] = values[index++];
541 if (count < 10)
542 fprintf(stderr, "\ntrans-load: warning:"
543 "Missing args for 'P'\n");
545 for (i = 0; i < count - 2; i++) {
546 ale_pos factor = (i % 2)
547 ? ((double) result.scaled_width() / width)
548 : ((double) result.scaled_height() / height);
550 x[i / 2][i % 2] *= factor;
553 if (tfile_input_version < 1) {
555 * Accommodate older versions
556 * of tfile.
558 for (i = 0; i < 4; i++) {
559 ale_pos y = x[i][0];
560 x[i][0] = x[i][1];
561 x[i][1] = y;
563 result.gpt_v0_set(x);
564 } else {
565 result.gpt_set(x);
568 *is_default = 0;
569 return result;
571 break;
572 case 'F':
573 case 'f':
574 if (is_primary)
575 break;
576 case 'E':
577 case 'e':
578 /* Euclidean transformation data */
580 double width, height;
581 double values[3] = {0, 0, 0};
582 int count, i;
583 ale_pos eu[3];
584 transformation::multi_coordinate mc1, mc2;
586 count = sscanf(line + 1, " %lf%lf%lf%lf%lf%d%d%d",
587 &width, &height,
588 &values[0], &values[1], &values[2],
589 &mc1.degree, &mc1.x, &mc1.y);
591 if (count == 8) {
592 mc2 = default_transform.get_current_coordinate();
594 if (mc1.degree < mc2.degree
595 || (mc1.degree == mc2.degree && mc1.y < mc2.y)
596 || (mc1.degree == mc2.degree && mc1.y == mc2.y && mc1.x < mc2.x))
597 break;
598 if (mc1.degree != mc2.degree
599 || mc1.x != mc2.x
600 || mc1.y != mc2.y) {
601 if (!result.exists(mc1))
602 break;
603 result.set_current_index(result.get_index(mc1));
608 eu[1] = values[0];
609 eu[0] = values[1];
610 eu[2] = values[2];
612 if (tfile_input_version < 2) {
613 ale_pos t = eu[0];
614 eu[0] = eu[1];
615 eu[1] = t;
619 if (count < 5)
620 fprintf(stderr, "\ntrans-load: warning:"
621 "Missing args for 'E'\n");
623 for (i = 0; (i < count - 2) && (i < 2); i++) {
624 ale_pos factor = (i % 2)
625 ? ((double) result.scaled_width() / width)
626 : ((double) result.scaled_height() / height);
628 eu[i] *= factor;
631 if (tfile_input_version < 1) {
632 result.eu_v0_set(eu);
633 } else {
634 result.eu_set(eu);
637 *is_default = 0;
638 return result;
640 break;
641 default:
642 fprintf(stderr,
643 "\ntrans-load: Error in tload_next: unrecognized command '%s'\n",
644 line);
645 exit(1);
649 return result;
653 * Create a new tsave_t transformation data file structure, used for
654 * writing data to transformation data files.
657 static inline struct tsave_t *tsave_new(const char *filename) {
658 FILE *file = fopen (filename, "w");
659 struct tsave_t *result = NULL;
661 if (!file) {
662 fprintf(stderr, "tsave: Error: could not open transformation data file '%s'.", filename);
663 exit(1);
666 result = (struct tsave_t *)
667 malloc(sizeof(struct tsave_t));
668 result->filename = filename;
669 result->file = file;
670 result->orig = "unknown";
671 result->target = "unknown";
673 fprintf(file, "# created by ALE transformation file handler version %d\n",
674 TFILE_VERSION);
676 fclose(file);
678 return result;
682 * Save the first transformation to a transformation data file associated with
683 * transformation data file structure T, or do nothing if T is NULL. This
684 * function also establishes the output file version.
686 * OFFSET is the transformation to be saved.
688 * IS_PROJECTIVE indicates whether to write a projective transformation.
692 static inline void tsave_first(struct tsave_t *t, transformation offset, int is_projective) {
694 if (t == NULL)
695 return;
697 t->file = fopen(t->filename, "a");
700 * Determine the output version to use. We use version 3 output syntax only when
701 * necessary. This comprises two cases:
703 * (i) an input file is used, and this file uses version 3 syntax.
704 * (ii) non-degenerate barrel distortion correction is selected.
706 * (i) can be directly examined. When (i) does not hold, (ii) can be
707 * inferred from offset.bd_count(), since this value should be constant
708 * when (i) does not hold. XXX: This logic should be reviewed.
711 if (tfile_input_version == 3 || offset.bd_count() > 0)
712 tfile_output_version = 3;
713 else
714 tfile_output_version = 2;
717 fprintf(t->file, "# producing transformation file syntax version %d\n", tfile_output_version);
718 fprintf(t->file, "V %d\n", tfile_output_version);
720 fprintf(t->file, "# Comment: Target output file is %s\n", t->target);
721 fprintf(t->file, "# Comment: Original frame is %s\n", t->orig);
723 if (tfile_output_version < 3) {
724 fclose(t->file);
725 return;
728 if (offset.bd_count() > 0) {
729 assert (tfile_output_version >= 3);
730 unsigned int i;
732 fprintf(t->file, "B ");
733 fprintf(t->file, "%u ", offset.bd_count());
734 for (i = 0; i < offset.bd_count(); i++)
735 fprintf(t->file, "%f ", (double) offset.bd_get(i));
736 fprintf(t->file, "\n");
740 if (is_projective) {
741 int i, j;
743 fprintf(t->file, "P ");
744 fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
745 for (i = 0; i < 4; i++)
746 for (j = 1; j >= 0; j--)
747 fprintf(t->file, "%f ", (double) offset.gpt_get(i, j));
748 } else {
749 fprintf(t->file, "E ");
750 fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
751 fprintf(t->file, "%f ", (double) offset.eu_get(1));
752 fprintf(t->file, "%f ", (double) offset.eu_get(0));
753 fprintf(t->file, "%f ", (double) offset.eu_get(2));
756 fprintf(t->file, "\n");
758 fclose(t->file);
762 * Save the next transformation to a transformation data file associated with
763 * transformation data file structure T, or do nothing if T is NULL.
765 * OFFSET is the transformation to be saved.
767 * IS_PROJECTIVE indicates whether to write a projective transformation.
769 * IS_PRIMARY indicates whether to write a primary transformation
773 static inline void tsave_next(struct tsave_t *t, transformation offset, int is_projective,
774 int is_primary) {
776 if (t == NULL)
777 return;
779 t->file = fopen(t->filename, "a");
781 if (is_primary && offset.bd_count() > 0) {
782 assert (tfile_output_version >= 3);
783 unsigned int i;
785 fprintf(t->file, "B ");
786 fprintf(t->file, "%u ", offset.bd_count());
787 for (i = 0; i < offset.bd_count(); i++)
788 fprintf(t->file, "%f ", (double) offset.bd_get(i));
789 fprintf(t->file, "\n");
792 if (is_projective) {
793 int i, j;
795 fprintf(t->file, is_primary ? "P " : "Q ");
796 fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
797 for (i = 0; i < 4; i++)
798 for (j = 1; j >= 0; j--)
799 fprintf(t->file, "%f ", (double) offset.gpt_get(i, j));
800 } else {
801 fprintf(t->file, is_primary ? "E " : "F ");
802 fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
803 fprintf(t->file, "%f ", (double) offset.eu_get(1));
804 fprintf(t->file, "%f ", (double) offset.eu_get(0));
805 fprintf(t->file, "%f ", (double) offset.eu_get(2));
808 if (!is_primary) {
809 transformation::multi_coordinate mc = offset.get_current_coordinate();
810 fprintf(t->file, "%d %d %d ", mc.degree, mc.x, mc.y);
813 fprintf(t->file, "\n");
815 fclose(t->file);
819 * Write information to a transformation file indicating the target output
820 * file.
823 static inline void tsave_target(struct tsave_t *t, const char *filename) {
824 if (t == NULL)
825 return;
827 t->target = filename;
828 if (t != NULL) {
829 t->file = fopen(t->filename, "a");
832 fclose(t->file);
837 * Write information to a transformation data file indicating the filename
838 * of the original frame (i.e. the first frame in the sequence of input
839 * frames).
842 static inline void tsave_orig(struct tsave_t *t, const char *filename) {
843 if (t == NULL)
844 return;
846 t->orig = filename;
850 * Write information to a transformation data file indicating the filename
851 * of a supplemental frame (i.e. a frame in the sequence of input frames
852 * that is not the first frame).
855 static inline void tsave_info(struct tsave_t *t, const char *filename) {
856 if (t != NULL) {
857 t->file = fopen(t->filename, "a");
859 fprintf(t->file, "# Comment: Supplemental frame %s\n", filename);
861 fclose(t->file);
866 * Write information to a transformation data file indicating the tonal
867 * registration multiplier.
870 static inline void tsave_trm(struct tsave_t *t, ale_real r, ale_real g, ale_real b) {
871 if (t != NULL) {
872 t->file = fopen(t->filename, "a");
874 fprintf(t->file, "# Comment: Exposure [r=%f g=%f b=%f]\n", (double) r, (double) g, (double) b);
876 fclose(t->file);
881 * Destroy a tload_t transformation data file structure.
884 static inline void tload_delete(struct tload_t *victim) {
885 if (victim)
886 fclose(victim->file);
887 free(victim);
891 * Destroy a tsave_t transformation data file structure.
894 static inline void tsave_delete(struct tsave_t *victim) {
895 free(victim);
898 #endif