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.
66 * Create a new tload_t transformation data file structure, used for
67 * reading data from transformation data files.
70 static inline struct tload_t
*tload_new(const char *filename
) {
71 FILE *file
= fopen (filename
, "r");
72 struct tload_t
*result
= NULL
;
75 fprintf(stderr
, "tload: Error: could not open transformation data file '%s'.", filename
);
79 result
= (struct tload_t
*)
80 malloc(sizeof(struct tload_t
));
81 result
->filename
= filename
;
88 * Load the first transformation from a transformation data file associated with
89 * transformation data file structure T, or return the default transformation
90 * if no transformation is available.
92 * T is a pointer to the tload_t transformation data file structure.
94 * IS_P is nonzero if a projective transformation is expected.
96 * DEFAULT_TRANSFORM is the default transformation result.
98 * IS_DEFAULT is used to signal a non-default transformation result.
101 static inline transformation
tload_first(struct tload_t
*t
, int is_p
,
102 transformation default_transform
, int *is_default
) {
104 transformation result
= default_transform
;
109 * If there is no file, return the default.
116 * Search through the initial part of the file to determine
126 first_character
= fgetc(t
->file
);
128 while (first_character
== ' '
129 || first_character
== 0xa
130 || first_character
== 0xd
131 || first_character
== '\t'
132 || first_character
== '#') {
133 ungetc(first_character
, t
->file
);
135 fgets(line
, 1024, t
->file
);
136 if (strlen(line
) >= 1023) {
138 "\ntrans-load: Error: line too long in input file\n");
142 first_character
= fgetc(t
->file
);
145 if (first_character
!= EOF
)
146 ungetc(first_character
, t
->file
);
149 * Check for version 0
152 if (first_character
!= 'V')
161 * Obtain version from version command string.
165 fgets(line
, 1024, t
->file
);
166 if (strlen(line
) >= 1023) {
168 "\ntrans-load: Error: line too long in input file\n");
172 int count
= sscanf(line
, "V %d", &tfile_input_version
);
175 fprintf(stderr
, "Error in transformation "
176 "file version command.\n");
178 } else if (tfile_input_version
> TFILE_VERSION_MAX
) {
179 fprintf(stderr
, "Unsupported transformation "
181 tfile_input_version
);
186 * Handle versions lower than 3.
189 if (tfile_input_version
< 3)
192 * Versions lower than 3 use the default transformation
193 * for the original frame.
199 * Read each line of the file until we find a transformation
203 while (!feof(t
->file
)) {
206 fgets(line
, 1024, t
->file
);
211 if (strlen(line
) >= 1023) {
213 "\ntrans-load: Error: line too long in input file\n");
223 /* Comment or whitespace */
227 /* Default transformation */
231 if (tfile_input_version
< 3) {
232 fprintf(stderr
, "\ntrans-load: Error: "
233 "Barrel distortion not supported "
234 "for version %d input files.\n"
235 "trans-load: Hint: Use version 3 "
236 "file syntax.\n", tfile_input_version
);
240 unsigned int pos
= 0, chars
;
242 double dparameters
[BARREL_DEGREE
];
243 ale_pos parameters
[BARREL_DEGREE
];
245 count
= sscanf(line
, "B %u%n", &bdc
, &chars
);
249 fprintf(stderr
, "\ntrans-load: Error: "
250 "Malformed 'B' command.\n");
254 if (bdc
> result
.bd_max()) {
255 fprintf(stderr
, "\ntrans-load: Error: "
256 "Barrel distortion degree %d "
257 "is too large. (Maximum is %d.)\n"
259 "Reduce degree or re-compile "
260 "with BD_DEGREE=%d\n", bdc
, BARREL_DEGREE
, bdc
);
264 for (unsigned int d
= 0; d
< bdc
; d
++) {
265 count
= sscanf(line
+ pos
, "%lf%n", &dparameters
[d
], &chars
);
269 fprintf(stderr
, "\ntrans-load: Error: "
270 "Malformed 'B' command.\n");
274 parameters
[d
] = dparameters
[d
];
277 result
.bd_set(bdc
, parameters
);
282 /* Projective transformation data */
285 fprintf(stderr
, "\ntrans-load: Error: "
286 "Projective data for euclidean "
289 "Use command-line option --projective.\n");
292 double width
, height
, values
[8];
296 count
= sscanf(line
+ 1, " %lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", &width
, &height
,
297 &values
[0], &values
[1], &values
[2], &values
[3],
298 &values
[4], &values
[5], &values
[6], &values
[7]);
301 for (int i
= 0; i
< 4; i
++)
302 for (int j
= 1; j
>= 0; j
--)
303 x
[i
][j
] = values
[index
++];
306 fprintf(stderr
, "\ntrans-load: warning:"
307 "Missing args for 'P'\n");
309 for (i
= 0; i
< count
- 2; i
++) {
310 ale_pos factor
= (i
% 2)
311 ? (result
.scaled_width() / width
)
312 : (result
.scaled_height() / height
);
314 x
[i
/ 2][i
% 2] *= factor
;
324 /* Euclidean transformation data */
327 double width
, height
;
328 double values
[3] = {0, 0, 0};
332 count
= sscanf(line
+ 1, " %lf%lf%lf%lf%lf",
334 &values
[0], &values
[1], &values
[2]);
341 fprintf(stderr
, "\ntrans-load: warning:"
342 "Missing args for 'E'\n");
344 for (i
= 0; (i
< count
- 2) && (i
< 2); i
++) {
345 ale_pos factor
= (i
% 2)
346 ? (result
.scaled_width() / width
)
347 : (result
.scaled_height() / height
);
359 "\ntrans-load: Error in tload_first: unrecognized command '%s'\n",
366 * EOF reached: return default transformation.
373 * Load the next transformation from a transformation data file associated with
374 * transformation data file structure T, or return the default transformation
375 * if no transformation is available.
377 * T is a pointer to the tload_t transformation data file structure.
379 * IS_P is nonzero if a projective transformation is expected.
381 * DEFAULT_TRANSFORM is the default transformation result.
383 * IS_DEFAULT is used to signal a non-default transformation result.
385 * IS_PRIMARY is used to differentiate primary and non-primary
389 static inline transformation
tload_next(struct tload_t
*t
, int is_p
,
390 transformation default_transform
, int *is_default
,
393 transformation result
= default_transform
;
398 * Read each line of the file until we find a transformation.
401 while (t
&& !feof(t
->file
)) {
403 char c
= fgetc(t
->file
);
404 if (!feof(t
->file
) && c
!= EOF
)
423 fgets(line
, 1024, t
->file
);
428 if (strlen(line
) >= 1023) {
430 "\ntrans-load: warning: line too long in input file\n");
439 /* Comment or whitespace */
443 /* Default transformation */
447 if (tfile_input_version
< 3) {
448 fprintf(stderr
, "\ntrans-load: Error: "
449 "Barrel distortion not supported "
450 "for version %d input files.\n"
451 "trans-load: Hint: Use version 3 "
452 "file syntax.\n", tfile_input_version
);
456 unsigned int pos
= 0, chars
;
458 ale_pos parameters
[BARREL_DEGREE
];
459 double dparameters
[BARREL_DEGREE
];
461 count
= sscanf(line
, "B %u%n", &bdc
, &chars
);
465 fprintf(stderr
, "\ntrans-load: Error: "
466 "Malformed 'B' command.\n");
470 if (bdc
> result
.bd_max()) {
471 fprintf(stderr
, "\ntrans-load: Error: "
472 "Barrel distortion degree %d "
473 "is too large. (Maximum is %d.)\n"
475 "Reduce degree or re-compile "
476 "with BD_DEGREE=%d\n", bdc
, BARREL_DEGREE
, bdc
);
480 for (unsigned int d
= 0; d
< bdc
; d
++) {
481 count
= sscanf(line
+ pos
, "%lf%n", &dparameters
[d
], &chars
);
485 fprintf(stderr
, "\ntrans-load: Error: "
486 "Malformed 'B' command.\n");
490 parameters
[d
] = dparameters
[d
];
493 result
.bd_set(bdc
, parameters
);
502 /* 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];
516 count
= sscanf(line
+ 1, " %lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", &width
, &height
,
517 &values
[0], &values
[1], &values
[2], &values
[3],
518 &values
[4], &values
[5], &values
[6], &values
[7]);
521 for (int i
= 0; i
< 4; i
++)
522 for (int j
= 1; j
>= 0; j
--)
523 x
[i
][j
] = values
[index
++];
526 fprintf(stderr
, "\ntrans-load: warning:"
527 "Missing args for 'P'\n");
529 for (i
= 0; i
< count
- 2; i
++) {
530 ale_pos factor
= (i
% 2)
531 ? (result
.scaled_width() / width
)
532 : (result
.scaled_height() / height
);
534 x
[i
/ 2][i
% 2] *= factor
;
537 if (tfile_input_version
< 1) {
539 * Accommodate older versions
542 for (i
= 0; i
< 4; i
++) {
547 result
.gpt_v0_set(x
);
561 /* Euclidean transformation data */
564 double width
, height
;
565 double values
[3] = {0, 0, 0};
569 count
= sscanf(line
+ 1, " %lf%lf%lf%lf%lf",
571 &values
[0], &values
[1], &values
[2]);
577 if (tfile_input_version
< 2) {
585 fprintf(stderr
, "\ntrans-load: warning:"
586 "Missing args for 'E'\n");
588 for (i
= 0; (i
< count
- 2) && (i
< 2); i
++) {
589 ale_pos factor
= (i
% 2)
590 ? (result
.scaled_width() / width
)
591 : (result
.scaled_height() / height
);
596 if (tfile_input_version
< 1) {
597 result
.eu_v0_set(eu
);
607 "\ntrans-load: Error in tload_next: unrecognized command '%s'\n",
617 * Create a new tsave_t transformation data file structure, used for
618 * writing data to transformation data files.
621 static inline struct tsave_t
*tsave_new(const char *filename
) {
622 FILE *file
= fopen (filename
, "w");
623 struct tsave_t
*result
= NULL
;
626 fprintf(stderr
, "tsave: Error: could not open transformation data file '%s'.", filename
);
630 result
= (struct tsave_t
*)
631 malloc(sizeof(struct tsave_t
));
632 result
->filename
= filename
;
634 result
->orig
= "unknown";
635 result
->target
= "unknown";
637 fprintf(file
, "# created by ALE transformation file handler version %d\n",
646 * Save the first transformation to a transformation data file associated with
647 * transformation data file structure T, or do nothing if T is NULL. This
648 * function also establishes the output file version.
650 * OFFSET is the transformation to be saved.
652 * IS_PROJECTIVE indicates whether to write a projective transformation.
656 static inline void tsave_first(struct tsave_t
*t
, transformation offset
, int is_projective
) {
661 t
->file
= fopen(t
->filename
, "a");
664 * Determine the output version to use. We use version 3 output syntax only when
665 * necessary. This comprises two cases:
667 * (i) an input file is used, and this file uses version 3 syntax.
668 * (ii) non-degenerate barrel distortion correction is selected.
670 * (i) can be directly examined. When (i) does not hold, (ii) can be
671 * inferred from offset.bd_count(), since this value should be constant
672 * when (i) does not hold. XXX: This logic should be reviewed.
675 if (tfile_input_version
== 3 || offset
.bd_count() > 0)
676 tfile_output_version
= 3;
678 tfile_output_version
= 2;
681 fprintf(t
->file
, "# producing transformation file syntax version %d\n", tfile_output_version
);
682 fprintf(t
->file
, "V %d\n", tfile_output_version
);
684 fprintf(t
->file
, "# Comment: Target output file is %s\n", t
->target
);
685 fprintf(t
->file
, "# Comment: Original frame is %s\n", t
->orig
);
686 fprintf(t
->file
, "# Comment: Avg magnitude [r=%f g=%f b=%f]\n", t
->orig_apm
[0], t
->orig_apm
[1], t
->orig_apm
[2]);
688 if (tfile_output_version
< 3) {
693 if (offset
.bd_count() > 0) {
694 assert (tfile_output_version
>= 3);
697 fprintf(t
->file
, "B ");
698 fprintf(t
->file
, "%u ", offset
.bd_count());
699 for (i
= 0; i
< offset
.bd_count(); i
++)
700 fprintf(t
->file
, "%f ", (double) offset
.bd_get(i
));
701 fprintf(t
->file
, "\n");
708 fprintf(t
->file
, "P ");
709 fprintf(t
->file
, "%f %f ", (double) offset
.scaled_width(), (double) offset
.scaled_height());
710 for (i
= 0; i
< 4; i
++)
711 for (j
= 1; j
>= 0; j
--)
712 fprintf(t
->file
, "%f ", (double) offset
.gpt_get(i
, j
));
714 fprintf(t
->file
, "E ");
715 fprintf(t
->file
, "%f %f ", (double) offset
.scaled_width(), (double) offset
.scaled_height());
716 fprintf(t
->file
, "%f ", (double) offset
.eu_get(1));
717 fprintf(t
->file
, "%f ", (double) offset
.eu_get(0));
718 fprintf(t
->file
, "%f ", (double) offset
.eu_get(2));
721 fprintf(t
->file
, "\n");
727 * Save the next transformation to a transformation data file associated with
728 * transformation data file structure T, or do nothing if T is NULL.
730 * OFFSET is the transformation to be saved.
732 * IS_PROJECTIVE indicates whether to write a projective transformation.
734 * IS_PRIMARY indicates whether to write a primary transformation
738 static inline void tsave_next(struct tsave_t
*t
, transformation offset
, int is_projective
,
744 t
->file
= fopen(t
->filename
, "a");
746 if (is_primary
&& offset
.bd_count() > 0) {
747 assert (tfile_output_version
>= 3);
750 fprintf(t
->file
, "B ");
751 fprintf(t
->file
, "%u ", offset
.bd_count());
752 for (i
= 0; i
< offset
.bd_count(); i
++)
753 fprintf(t
->file
, "%f ", (double) offset
.bd_get(i
));
754 fprintf(t
->file
, "\n");
760 fprintf(t
->file
, is_primary
? "P " : "Q ");
761 fprintf(t
->file
, "%f %f ", (double) offset
.scaled_width(), (double) offset
.scaled_height());
762 for (i
= 0; i
< 4; i
++)
763 for (j
= 1; j
>= 0; j
--)
764 fprintf(t
->file
, "%f ", (double) offset
.gpt_get(i
, j
));
766 fprintf(t
->file
, is_primary
? "E " : "F ");
767 fprintf(t
->file
, "%f %f ", (double) offset
.scaled_width(), (double) offset
.scaled_height());
768 fprintf(t
->file
, "%f ", (double) offset
.eu_get(1));
769 fprintf(t
->file
, "%f ", (double) offset
.eu_get(0));
770 fprintf(t
->file
, "%f ", (double) offset
.eu_get(2));
773 fprintf(t
->file
, "\n");
779 * Write information to a transformation file indicating the target output
783 static inline void tsave_target(struct tsave_t
*t
, const char *filename
) {
787 t
->target
= filename
;
789 t
->file
= fopen(t
->filename
, "a");
797 * Write information to a transformation data file indicating the filename
798 * of the original frame (i.e. the first frame in the sequence of input
802 static inline void tsave_orig(struct tsave_t
*t
, const char *filename
, pixel apm
) {
811 * Write information to a transformation data file indicating the filename
812 * of a supplemental frame (i.e. a frame in the sequence of input frames
813 * that is not the first frame).
816 static inline void tsave_info(struct tsave_t
*t
, const char *filename
) {
818 t
->file
= fopen(t
->filename
, "a");
820 fprintf(t
->file
, "# Comment: Supplemental frame %s\n", filename
);
827 * Write information to a transformation data file indicating the tonal
828 * registration multiplier.
831 static inline void tsave_trm(struct tsave_t
*t
, ale_real r
, ale_real g
, ale_real b
) {
833 t
->file
= fopen(t
->filename
, "a");
835 fprintf(t
->file
, "# Comment: Exposure [r=%f g=%f b=%f]\n", r
, g
, b
);
842 * Write information to a transformation data file indicating the average
846 static inline void tsave_apm(struct tsave_t
*t
, ale_real r
, ale_real g
, ale_real b
) {
848 t
->file
= fopen(t
->filename
, "a");
850 fprintf(t
->file
, "# Comment: Avg magnitude [r=%f g=%f b=%f]\n", r
, g
, b
);
858 * Destroy a tload_t transformation data file structure.
861 static inline void tload_delete(struct tload_t
*victim
) {
863 fclose(victim
->file
);
868 * Destroy a tsave_t transformation data file structure.
871 static inline void tsave_delete(struct tsave_t
*victim
) {