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 fgets(line
, 1024, t
->file
);
135 if (strlen(line
) >= 1023) {
137 "\ntrans-load: Error: line too long in input file\n");
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')
160 * Obtain version from version command string.
164 fgets(line
, 1024, t
->file
);
165 if (strlen(line
) >= 1023) {
167 "\ntrans-load: Error: line too long in input file\n");
171 int count
= sscanf(line
, "V %d", &tfile_input_version
);
174 fprintf(stderr
, "Error in transformation "
175 "file version command.\n");
177 } else if (tfile_input_version
> TFILE_VERSION_MAX
) {
178 fprintf(stderr
, "Unsupported transformation "
180 tfile_input_version
);
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.
198 * Read each line of the file until we find a transformation
202 while (!feof(t
->file
)) {
205 fgets(line
, 1024, t
->file
);
210 if (strlen(line
) >= 1023) {
212 "\ntrans-load: Error: line too long in input file\n");
222 /* Comment or whitespace */
226 /* Default transformation */
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
);
239 unsigned int pos
= 0, chars
;
241 double dparameters
[BARREL_DEGREE
];
242 ale_pos parameters
[BARREL_DEGREE
];
244 count
= sscanf(line
, "B %u%n", &bdc
, &chars
);
248 fprintf(stderr
, "\ntrans-load: Error: "
249 "Malformed 'B' command.\n");
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"
258 "Reduce degree or re-compile "
259 "with BD_DEGREE=%d\n", bdc
, BARREL_DEGREE
, bdc
);
263 for (unsigned int d
= 0; d
< bdc
; d
++) {
264 count
= sscanf(line
+ pos
, "%lf%n", &dparameters
[d
], &chars
);
268 fprintf(stderr
, "\ntrans-load: Error: "
269 "Malformed 'B' command.\n");
273 parameters
[d
] = dparameters
[d
];
276 result
.bd_set(bdc
, parameters
);
281 /* Projective transformation data */
284 fprintf(stderr
, "\ntrans-load: Error: "
285 "Projective data for euclidean "
288 "Use command-line option --projective.\n");
291 double width
, height
, values
[8];
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]);
300 for (int i
= 0; i
< 4; i
++)
301 for (int j
= 1; j
>= 0; j
--)
302 x
[i
][j
] = values
[index
++];
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
;
323 /* Euclidean transformation data */
326 double width
, height
;
327 double values
[3] = {0, 0, 0};
331 count
= sscanf(line
+ 1, " %lf%lf%lf%lf%lf",
333 &values
[0], &values
[1], &values
[2]);
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
);
358 "\ntrans-load: Error in tload_first: unrecognized command '%s'\n",
365 * EOF reached: return default transformation.
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
388 static inline transformation
tload_next(struct tload_t
*t
, int is_p
,
389 transformation default_transform
, int *is_default
,
392 transformation result
= default_transform
;
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
)
422 fgets(line
, 1024, t
->file
);
427 if (strlen(line
) >= 1023) {
429 "\ntrans-load: warning: line too long in input file\n");
438 /* Comment or whitespace */
442 /* Default transformation */
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
);
455 unsigned int pos
= 0, chars
;
457 ale_pos parameters
[BARREL_DEGREE
];
458 double dparameters
[BARREL_DEGREE
];
460 count
= sscanf(line
, "B %u%n", &bdc
, &chars
);
464 fprintf(stderr
, "\ntrans-load: Error: "
465 "Malformed 'B' command.\n");
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"
474 "Reduce degree or re-compile "
475 "with BD_DEGREE=%d\n", bdc
, BARREL_DEGREE
, bdc
);
479 for (unsigned int d
= 0; d
< bdc
; d
++) {
480 count
= sscanf(line
+ pos
, "%lf%n", &dparameters
[d
], &chars
);
484 fprintf(stderr
, "\ntrans-load: Error: "
485 "Malformed 'B' command.\n");
489 parameters
[d
] = dparameters
[d
];
492 result
.bd_set(bdc
, parameters
);
501 /* Projective transformation data */
503 fprintf(stderr
, "\ntrans-load: Error: "
504 "Projective data for euclidean "
507 "Use command-line option --projective.\n");
510 double width
, height
, values
[8];
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
);
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
))
527 if (mc1
.degree
!= mc2
.degree
530 if (!result
.exists(mc1
))
532 result
.set_current_index(result
.get_index(mc1
));
537 for (int i
= 0; i
< 4; i
++)
538 for (int j
= 1; j
>= 0; j
--)
539 x
[i
][j
] = values
[index
++];
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
558 for (i
= 0; i
< 4; i
++) {
563 result
.gpt_v0_set(x
);
578 /* Euclidean transformation data */
580 double width
, height
;
581 double values
[3] = {0, 0, 0};
584 transformation::multi_coordinate mc1
, mc2
;
586 count
= sscanf(line
+ 1, " %lf%lf%lf%lf%lf%d%d%d",
588 &values
[0], &values
[1], &values
[2],
589 &mc1
.degree
, &mc1
.x
, &mc1
.y
);
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
))
598 if (mc1
.degree
!= mc2
.degree
601 if (!result
.exists(mc1
))
603 result
.set_current_index(result
.get_index(mc1
));
612 if (tfile_input_version
< 2) {
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
);
631 if (tfile_input_version
< 1) {
632 result
.eu_v0_set(eu
);
643 "\ntrans-load: Error in tload_next: unrecognized command '%s'\n",
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
;
662 fprintf(stderr
, "tsave: Error: could not open transformation data file '%s'.", filename
);
666 result
= (struct tsave_t
*)
667 malloc(sizeof(struct tsave_t
));
668 result
->filename
= filename
;
670 result
->orig
= "unknown";
671 result
->target
= "unknown";
673 fprintf(file
, "# created by ALE transformation file handler version %d\n",
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
) {
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;
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) {
728 if (offset
.bd_count() > 0) {
729 assert (tfile_output_version
>= 3);
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");
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
));
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");
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
,
779 t
->file
= fopen(t
->filename
, "a");
781 if (is_primary
&& offset
.bd_count() > 0) {
782 assert (tfile_output_version
>= 3);
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");
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
));
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));
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");
819 * Write information to a transformation file indicating the target output
823 static inline void tsave_target(struct tsave_t
*t
, const char *filename
) {
827 t
->target
= filename
;
829 t
->file
= fopen(t
->filename
, "a");
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
842 static inline void tsave_orig(struct tsave_t
*t
, const char *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
) {
857 t
->file
= fopen(t
->filename
, "a");
859 fprintf(t
->file
, "# Comment: Supplemental frame %s\n", filename
);
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
) {
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
);
881 * Destroy a tload_t transformation data file structure.
884 static inline void tload_delete(struct tload_t
*victim
) {
886 fclose(victim
->file
);
891 * Destroy a tsave_t transformation data file structure.
894 static inline void tsave_delete(struct tsave_t
*victim
) {