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.
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.
54 * Structure to describe a transformation data file to write data to.
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
;
74 fprintf(stderr
, "tload: Error: could not open transformation data file '%s'.", filename
);
78 result
= (struct tload_t
*)
79 malloc(sizeof(struct tload_t
));
80 result
->filename
= filename
;
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
;
108 * If there is no file, return the default.
115 * Search through the initial part of the file to determine
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
);
134 char *fgets_result
= fgets(line
, 1024, t
->file
);
136 assert(fgets_result
);
138 if (strlen(line
) >= 1023) {
140 "\ntrans-load: Error: line too long in input file\n");
144 first_character
= fgetc(t
->file
);
147 if (first_character
!= EOF
)
148 ungetc(first_character
, t
->file
);
151 * Check for version 0
154 if (first_character
!= 'V')
163 * Obtain version from version command string.
167 char *fgets_result
= fgets(line
, 1024, t
->file
);
169 assert(fgets_result
);
171 if (strlen(line
) >= 1023) {
173 "\ntrans-load: Error: line too long in input file\n");
177 int count
= sscanf(line
, "V %d", &tfile_input_version
);
180 fprintf(stderr
, "Error in transformation "
181 "file version command.\n");
183 } else if (tfile_input_version
> TFILE_VERSION_MAX
) {
184 fprintf(stderr
, "Unsupported transformation "
186 tfile_input_version
);
191 * Handle versions lower than 3.
194 if (tfile_input_version
< 3)
197 * Versions lower than 3 use the default transformation
198 * for the original frame.
204 * Read each line of the file until we find a transformation
208 while (!feof(t
->file
)) {
211 if(!fgets(line
, 1024, t
->file
))
214 if (strlen(line
) >= 1023) {
216 "\ntrans-load: Error: line too long in input file\n");
226 /* Comment or whitespace */
230 /* Default transformation */
234 if (tfile_input_version
< 3) {
235 fprintf(stderr
, "\ntrans-load: Error: "
236 "Barrel distortion not supported "
237 "for version %d input files.\n"
238 "trans-load: Hint: Use version 3 "
239 "file syntax.\n", tfile_input_version
);
243 unsigned int pos
= 0, chars
;
245 double dparameters
[BARREL_DEGREE
];
246 ale_pos parameters
[BARREL_DEGREE
];
248 count
= sscanf(line
, "B %u%n", &bdc
, &chars
);
252 fprintf(stderr
, "\ntrans-load: Error: "
253 "Malformed 'B' command.\n");
257 if (bdc
> result
.bd_max()) {
258 fprintf(stderr
, "\ntrans-load: Error: "
259 "Barrel distortion degree %d "
260 "is too large. (Maximum is %d.)\n"
262 "Reduce degree or re-compile "
263 "with BD_DEGREE=%d\n", bdc
, BARREL_DEGREE
, bdc
);
267 for (unsigned int d
= 0; d
< bdc
; d
++) {
268 count
= sscanf(line
+ pos
, "%lf%n", &dparameters
[d
], &chars
);
272 fprintf(stderr
, "\ntrans-load: Error: "
273 "Malformed 'B' command.\n");
277 parameters
[d
] = dparameters
[d
];
280 result
.bd_set(bdc
, parameters
);
285 /* Projective transformation data */
288 fprintf(stderr
, "\ntrans-load: Error: "
289 "Projective data for euclidean "
292 "Use command-line option --projective.\n");
295 double width
, height
, values
[8];
299 count
= sscanf(line
+ 1, " %lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", &width
, &height
,
300 &values
[0], &values
[1], &values
[2], &values
[3],
301 &values
[4], &values
[5], &values
[6], &values
[7]);
304 for (int i
= 0; i
< 4; i
++)
305 for (int j
= 1; j
>= 0; j
--)
306 x
[i
][j
] = values
[index
++];
309 fprintf(stderr
, "\ntrans-load: warning:"
310 "Missing args for 'P'\n");
312 for (i
= 0; i
< count
- 2; i
++) {
313 ale_pos factor
= (i
% 2)
314 ? ((double) result
.scaled_width() / width
)
315 : ((double) result
.scaled_height() / height
);
317 x
[i
/ 2][i
% 2] *= factor
;
327 /* Euclidean transformation data */
330 double width
, height
;
331 double values
[3] = {0, 0, 0};
335 count
= sscanf(line
+ 1, " %lf%lf%lf%lf%lf",
337 &values
[0], &values
[1], &values
[2]);
344 fprintf(stderr
, "\ntrans-load: warning:"
345 "Missing args for 'E'\n");
347 for (i
= 0; (i
< count
- 2) && (i
< 2); i
++) {
348 ale_pos factor
= (i
% 2)
349 ? ((double) result
.scaled_width() / width
)
350 : ((double) result
.scaled_height() / height
);
362 "\ntrans-load: Error in tload_first: unrecognized command '%s'\n",
369 * EOF reached: return default transformation.
376 * Load the next transformation from a transformation data file associated with
377 * transformation data file structure T, or return the default transformation
378 * if no transformation is available.
380 * T is a pointer to the tload_t transformation data file structure.
382 * IS_P is nonzero if a projective transformation is expected.
384 * DEFAULT_TRANSFORM is the default transformation result.
386 * IS_DEFAULT is used to signal a non-default transformation result.
388 * IS_PRIMARY is used to differentiate primary and non-primary
392 static inline transformation
tload_next(struct tload_t
*t
, int is_p
,
393 transformation default_transform
, int *is_default
,
396 transformation result
= default_transform
;
401 * Read each line of the file until we find a transformation.
404 while (t
&& !feof(t
->file
)) {
406 char c
= fgetc(t
->file
);
407 if (!feof(t
->file
) && c
!= EOF
)
426 if (!fgets(line
, 1024, t
->file
))
429 if (strlen(line
) >= 1023) {
431 "\ntrans-load: warning: line too long in input file\n");
440 /* Comment or whitespace */
444 /* Default transformation */
448 if (tfile_input_version
< 3) {
449 fprintf(stderr
, "\ntrans-load: Error: "
450 "Barrel distortion not supported "
451 "for version %d input files.\n"
452 "trans-load: Hint: Use version 3 "
453 "file syntax.\n", tfile_input_version
);
457 unsigned int pos
= 0, chars
;
459 ale_pos parameters
[BARREL_DEGREE
];
460 double dparameters
[BARREL_DEGREE
];
462 count
= sscanf(line
, "B %u%n", &bdc
, &chars
);
466 fprintf(stderr
, "\ntrans-load: Error: "
467 "Malformed 'B' command.\n");
471 if (bdc
> result
.bd_max()) {
472 fprintf(stderr
, "\ntrans-load: Error: "
473 "Barrel distortion degree %d "
474 "is too large. (Maximum is %d.)\n"
476 "Reduce degree or re-compile "
477 "with BD_DEGREE=%d\n", bdc
, BARREL_DEGREE
, bdc
);
481 for (unsigned int d
= 0; d
< bdc
; d
++) {
482 count
= sscanf(line
+ pos
, "%lf%n", &dparameters
[d
], &chars
);
486 fprintf(stderr
, "\ntrans-load: Error: "
487 "Malformed 'B' command.\n");
491 parameters
[d
] = dparameters
[d
];
494 result
.bd_set(bdc
, parameters
);
503 /* Projective transformation data */
505 fprintf(stderr
, "\ntrans-load: Error: "
506 "Projective data for euclidean "
509 "Use command-line option --projective.\n");
512 double width
, height
, values
[8];
515 transformation::multi_coordinate mc1
, mc2
;
517 count
= sscanf(line
+ 1, " %lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%d%d%d", &width
, &height
,
518 &values
[0], &values
[1], &values
[2], &values
[3],
519 &values
[4], &values
[5], &values
[6], &values
[7],
520 &mc1
.degree
, &mc1
.x
, &mc1
.y
);
523 mc2
= default_transform
.get_current_coordinate();
525 if (mc1
.degree
< mc2
.degree
526 || (mc1
.degree
== mc2
.degree
&& mc1
.y
< mc2
.y
)
527 || (mc1
.degree
== mc2
.degree
&& mc1
.y
== mc2
.y
&& mc1
.x
< mc2
.x
))
529 if (mc1
.degree
!= mc2
.degree
532 if (!result
.exists(mc1
))
534 result
.set_current_index(result
.get_index(mc1
));
539 for (int i
= 0; i
< 4; i
++)
540 for (int j
= 1; j
>= 0; j
--)
541 x
[i
][j
] = values
[index
++];
544 fprintf(stderr
, "\ntrans-load: warning:"
545 "Missing args for 'P'\n");
547 for (i
= 0; i
< count
- 2; i
++) {
548 ale_pos factor
= (i
% 2)
549 ? ((double) result
.scaled_width() / width
)
550 : ((double) result
.scaled_height() / height
);
552 x
[i
/ 2][i
% 2] *= factor
;
555 if (tfile_input_version
< 1) {
557 * Accommodate older versions
560 for (i
= 0; i
< 4; i
++) {
565 result
.gpt_v0_set(x
);
580 /* Euclidean transformation data */
582 double width
, height
;
583 double values
[3] = {0, 0, 0};
586 transformation::multi_coordinate mc1
, mc2
;
588 count
= sscanf(line
+ 1, " %lf%lf%lf%lf%lf%d%d%d",
590 &values
[0], &values
[1], &values
[2],
591 &mc1
.degree
, &mc1
.x
, &mc1
.y
);
594 mc2
= default_transform
.get_current_coordinate();
596 if (mc1
.degree
< mc2
.degree
597 || (mc1
.degree
== mc2
.degree
&& mc1
.y
< mc2
.y
)
598 || (mc1
.degree
== mc2
.degree
&& mc1
.y
== mc2
.y
&& mc1
.x
< mc2
.x
))
600 if (mc1
.degree
!= mc2
.degree
603 if (!result
.exists(mc1
))
605 result
.set_current_index(result
.get_index(mc1
));
614 if (tfile_input_version
< 2) {
622 fprintf(stderr
, "\ntrans-load: warning:"
623 "Missing args for 'E'\n");
625 for (i
= 0; (i
< count
- 2) && (i
< 2); i
++) {
626 ale_pos factor
= (i
% 2)
627 ? ((double) result
.scaled_width() / width
)
628 : ((double) result
.scaled_height() / height
);
633 if (tfile_input_version
< 1) {
634 result
.eu_v0_set(eu
);
645 "\ntrans-load: Error in tload_next: unrecognized command '%s'\n",
655 * Create a new tsave_t transformation data file structure, used for
656 * writing data to transformation data files.
659 static inline struct tsave_t
*tsave_new(const char *filename
) {
660 FILE *file
= fopen (filename
, "w");
661 struct tsave_t
*result
= NULL
;
664 fprintf(stderr
, "tsave: Error: could not open transformation data file '%s'.", filename
);
668 result
= (struct tsave_t
*)
669 malloc(sizeof(struct tsave_t
));
670 result
->filename
= filename
;
672 result
->orig
= "unknown";
673 result
->target
= "unknown";
675 fprintf(file
, "# created by ALE transformation file handler version %d\n",
684 * Save the first transformation to a transformation data file associated with
685 * transformation data file structure T, or do nothing if T is NULL. This
686 * function also establishes the output file version.
688 * OFFSET is the transformation to be saved.
690 * IS_PROJECTIVE indicates whether to write a projective transformation.
694 static inline void tsave_first(struct tsave_t
*t
, transformation offset
, int is_projective
) {
699 t
->file
= fopen(t
->filename
, "a");
702 * Determine the output version to use. We use version 3 output syntax only when
703 * necessary. This comprises two cases:
705 * (i) an input file is used, and this file uses version 3 syntax.
706 * (ii) non-degenerate barrel distortion correction is selected.
708 * (i) can be directly examined. When (i) does not hold, (ii) can be
709 * inferred from offset.bd_count(), since this value should be constant
710 * when (i) does not hold. XXX: This logic should be reviewed.
713 if (tfile_input_version
== 3 || offset
.bd_count() > 0)
714 tfile_output_version
= 3;
716 tfile_output_version
= 2;
719 fprintf(t
->file
, "# producing transformation file syntax version %d\n", tfile_output_version
);
720 fprintf(t
->file
, "V %d\n", tfile_output_version
);
722 fprintf(t
->file
, "# Comment: Target output file is %s\n", t
->target
);
723 fprintf(t
->file
, "# Comment: Original frame is %s\n", t
->orig
);
725 if (tfile_output_version
< 3) {
730 if (offset
.bd_count() > 0) {
731 assert (tfile_output_version
>= 3);
734 fprintf(t
->file
, "B ");
735 fprintf(t
->file
, "%u ", offset
.bd_count());
736 for (i
= 0; i
< offset
.bd_count(); i
++)
737 fprintf(t
->file
, "%f ", (double) offset
.bd_get(i
));
738 fprintf(t
->file
, "\n");
745 fprintf(t
->file
, "P ");
746 fprintf(t
->file
, "%f %f ", (double) offset
.scaled_width(), (double) offset
.scaled_height());
747 for (i
= 0; i
< 4; i
++)
748 for (j
= 1; j
>= 0; j
--)
749 fprintf(t
->file
, "%f ", (double) offset
.gpt_get(i
, j
));
751 fprintf(t
->file
, "E ");
752 fprintf(t
->file
, "%f %f ", (double) offset
.scaled_width(), (double) offset
.scaled_height());
753 fprintf(t
->file
, "%f ", (double) offset
.eu_get(1));
754 fprintf(t
->file
, "%f ", (double) offset
.eu_get(0));
755 fprintf(t
->file
, "%f ", (double) offset
.eu_get(2));
758 fprintf(t
->file
, "\n");
764 * Save the next transformation to a transformation data file associated with
765 * transformation data file structure T, or do nothing if T is NULL.
767 * OFFSET is the transformation to be saved.
769 * IS_PROJECTIVE indicates whether to write a projective transformation.
771 * IS_PRIMARY indicates whether to write a primary transformation
775 static inline void tsave_next(struct tsave_t
*t
, transformation offset
, int is_projective
,
781 t
->file
= fopen(t
->filename
, "a");
783 if (is_primary
&& offset
.bd_count() > 0) {
784 assert (tfile_output_version
>= 3);
787 fprintf(t
->file
, "B ");
788 fprintf(t
->file
, "%u ", offset
.bd_count());
789 for (i
= 0; i
< offset
.bd_count(); i
++)
790 fprintf(t
->file
, "%f ", (double) offset
.bd_get(i
));
791 fprintf(t
->file
, "\n");
797 fprintf(t
->file
, is_primary
? "P " : "Q ");
798 fprintf(t
->file
, "%f %f ", (double) offset
.scaled_width(), (double) offset
.scaled_height());
799 for (i
= 0; i
< 4; i
++)
800 for (j
= 1; j
>= 0; j
--)
801 fprintf(t
->file
, "%f ", (double) offset
.gpt_get(i
, j
));
803 fprintf(t
->file
, is_primary
? "E " : "F ");
804 fprintf(t
->file
, "%f %f ", (double) offset
.scaled_width(), (double) offset
.scaled_height());
805 fprintf(t
->file
, "%f ", (double) offset
.eu_get(1));
806 fprintf(t
->file
, "%f ", (double) offset
.eu_get(0));
807 fprintf(t
->file
, "%f ", (double) offset
.eu_get(2));
811 transformation::multi_coordinate mc
= offset
.get_current_coordinate();
812 fprintf(t
->file
, "%d %d %d ", mc
.degree
, mc
.x
, mc
.y
);
815 fprintf(t
->file
, "\n");
821 * Write information to a transformation file indicating the target output
825 static inline void tsave_target(struct tsave_t
*t
, const char *filename
) {
829 t
->target
= filename
;
831 t
->file
= fopen(t
->filename
, "a");
839 * Write information to a transformation data file indicating the filename
840 * of the original frame (i.e. the first frame in the sequence of input
844 static inline void tsave_orig(struct tsave_t
*t
, const char *filename
) {
852 * Write information to a transformation data file indicating the filename
853 * of a supplemental frame (i.e. a frame in the sequence of input frames
854 * that is not the first frame).
857 static inline void tsave_info(struct tsave_t
*t
, const char *filename
) {
859 t
->file
= fopen(t
->filename
, "a");
861 fprintf(t
->file
, "# Comment: Supplemental frame %s\n", filename
);
868 * Write information to a transformation data file indicating the tonal
869 * registration multiplier.
872 static inline void tsave_trm(struct tsave_t
*t
, ale_real r
, ale_real g
, ale_real b
) {
874 t
->file
= fopen(t
->filename
, "a");
876 fprintf(t
->file
, "# Comment: Exposure [r=%f g=%f b=%f]\n", (double) r
, (double) g
, (double) b
);
883 * Destroy a tload_t transformation data file structure.
886 static inline void tload_delete(struct tload_t
*victim
) {
888 fclose(victim
->file
);
893 * Destroy a tsave_t transformation data file structure.
896 static inline void tsave_delete(struct tsave_t
*victim
) {