TODO: Collapse darcs repositories 'ale' and 'ale-working' into a single repository.
[Ale.git] / d2 / tfile.h
blobfe011b689d1840bbb5869a5b3b19f9ff25306731
1 // Copyright 2002, 2003 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 2 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 pixel orig_apm;
62 FILE *file;
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;
74 if (!file) {
75 fprintf(stderr, "tload: Error: could not open transformation data file '%s'.", filename);
76 exit(1);
79 result = (struct tload_t *)
80 malloc(sizeof(struct tload_t));
81 result->filename = filename;
82 result->file = file;
84 return result;
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;
106 *is_default = 1;
109 * If there is no file, return the default.
112 if (t == NULL)
113 return result;
116 * Search through the initial part of the file to determine
117 * its version.
121 * Skip comments
124 int first_character;
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);
134 char line[1024];
135 fgets(line, 1024, t->file);
136 if (strlen(line) >= 1023) {
137 fprintf(stderr,
138 "\ntrans-load: Error: line too long in input file\n");
139 exit(1);
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')
155 * Must be version 0.
158 return result;
161 * Obtain version from version command string.
164 char line[1024];
165 fgets(line, 1024, t->file);
166 if (strlen(line) >= 1023) {
167 fprintf(stderr,
168 "\ntrans-load: Error: line too long in input file\n");
169 exit(1);
172 int count = sscanf(line, "V %d", &tfile_input_version);
174 if (count < 1) {
175 fprintf(stderr, "Error in transformation "
176 "file version command.\n");
177 exit(1);
178 } else if (tfile_input_version > TFILE_VERSION_MAX) {
179 fprintf(stderr, "Unsupported transformation "
180 "file version %d\n",
181 tfile_input_version);
182 exit(1);
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.
196 return result;
199 * Read each line of the file until we find a transformation
200 * or EOF.
203 while (!feof(t->file)) {
204 char line[1024];
206 fgets(line, 1024, t->file);
208 if (feof(t->file))
209 return result;
211 if (strlen(line) >= 1023) {
212 fprintf(stderr,
213 "\ntrans-load: Error: line too long in input file\n");
214 exit(1);
217 switch (line[0]) {
218 case ' ':
219 case 0xa:
220 case 0xd:
221 case '\t':
222 case '#':
223 /* Comment or whitespace */
224 break;
225 case 'D':
226 case 'd':
227 /* Default transformation */
228 return result;
229 case 'B':
230 case 'b':
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);
237 exit(1);
238 } else {
239 unsigned int count;
240 unsigned int pos = 0, chars;
241 unsigned int bdc;
242 double dparameters[BARREL_DEGREE];
243 ale_pos parameters[BARREL_DEGREE];
245 count = sscanf(line, "B %u%n", &bdc, &chars);
246 pos += chars;
248 if (count < 1) {
249 fprintf(stderr, "\ntrans-load: Error: "
250 "Malformed 'B' command.\n");
251 exit(1);
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"
258 "trans-load: Hint: "
259 "Reduce degree or re-compile "
260 "with BD_DEGREE=%d\n", bdc, BARREL_DEGREE, bdc);
261 exit(1);
264 for (unsigned int d = 0; d < bdc; d++) {
265 count = sscanf(line + pos, "%lf%n", &dparameters[d], &chars);
266 pos += chars;
268 if (count < 1) {
269 fprintf(stderr, "\ntrans-load: Error: "
270 "Malformed 'B' command.\n");
271 exit(1);
274 parameters[d] = dparameters[d];
277 result.bd_set(bdc, parameters);
279 break;
280 case 'P':
281 case 'p':
282 /* Projective transformation data */
283 *is_default = 0;
284 if (is_p == 0) {
285 fprintf(stderr, "\ntrans-load: Error: "
286 "Projective data for euclidean "
287 "transformation.\n"
288 "trans-load: Hint: "
289 "Use command-line option --projective.\n");
290 exit(1);
291 } else {
292 double width, height, values[8];
293 int count, i;
294 point x[4];
296 count = sscanf(line, "P %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]);
300 int index = 0;
301 for (int i = 0; i < 4; i++)
302 for (int j = 1; j >= 0; j--)
303 x[i][j] = values[index++];
305 if (count < 10)
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;
317 result.gpt_set(x);
319 return result;
321 break;
322 case 'E':
323 case 'e':
324 /* Euclidean transformation data */
325 *is_default = 0;
327 double width, height;
328 double values[3] = {0, 0, 0};
329 int count, i;
330 ale_pos eu[3];
332 count = sscanf(line, "E %lf%lf%lf%lf%lf",
333 &width, &height,
334 &values[0], &values[1], &values[2]);
336 eu[1] = values[0];
337 eu[0] = values[1];
338 eu[2] = values[2];
340 if (count < 5)
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);
349 eu[i] *= factor;
352 result.eu_set(eu);
354 return result;
356 break;
357 default:
358 fprintf(stderr,
359 "\ntrans-load: Error in tload_first: unrecognized command '%s'\n",
360 line);
361 exit(1);
366 * EOF reached: return default transformation.
369 return result;
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.
386 static inline transformation tload_next(struct tload_t *t, int is_p,
387 transformation default_transform, int *is_default) {
389 transformation result = default_transform;
391 *is_default = 1;
394 * Read each line of the file until we find a transformation.
397 while (t && !feof(t->file)) {
398 char line[1024];
400 fgets(line, 1024, t->file);
402 if (feof(t->file))
403 return result;
405 if (strlen(line) >= 1023) {
406 fprintf(stderr,
407 "\ntrans-load: warning: line too long in input file\n");
410 switch (line[0]) {
411 case ' ':
412 case 0xa:
413 case 0xd:
414 case '\t':
415 case '#':
416 /* Comment or whitespace */
417 break;
418 case 'D':
419 case 'd':
420 /* Default transformation */
421 return result;
422 case 'B':
423 case 'b':
424 if (tfile_input_version < 3) {
425 fprintf(stderr, "\ntrans-load: Error: "
426 "Barrel distortion not supported "
427 "for version %d input files.\n"
428 "trans-load: Hint: Use version 3 "
429 "file syntax.\n", tfile_input_version);
430 exit(1);
431 } else {
432 unsigned int count;
433 unsigned int pos = 0, chars;
434 unsigned int bdc;
435 ale_pos parameters[BARREL_DEGREE];
436 double dparameters[BARREL_DEGREE];
438 count = sscanf(line, "B %u%n", &bdc, &chars);
439 pos += chars;
441 if (count < 1) {
442 fprintf(stderr, "\ntrans-load: Error: "
443 "Malformed 'B' command.\n");
444 exit(1);
447 if (bdc > result.bd_max()) {
448 fprintf(stderr, "\ntrans-load: Error: "
449 "Barrel distortion degree %d "
450 "is too large. (Maximum is %d.)\n"
451 "trans-load: Hint: "
452 "Reduce degree or re-compile "
453 "with BD_DEGREE=%d\n", bdc, BARREL_DEGREE, bdc);
454 exit(1);
457 for (unsigned int d = 0; d < bdc; d++) {
458 count = sscanf(line + pos, "%lf%n", &dparameters[d], &chars);
459 pos += chars;
461 if (count < 1) {
462 fprintf(stderr, "\ntrans-load: Error: "
463 "Malformed 'B' command.\n");
464 exit(1);
467 parameters[d] = dparameters[d];
470 result.bd_set(bdc, parameters);
472 break;
473 case 'P':
474 case 'p':
475 /* Projective transformation data */
476 *is_default = 0;
477 if (is_p == 0) {
478 fprintf(stderr, "\ntrans-load: Error: "
479 "Projective data for euclidean "
480 "transformation.\n"
481 "trans-load: Hint: "
482 "Use command-line option --projective.\n");
483 exit(1);
484 } else {
485 double width, height, values[8];
486 int count, i;
487 point x[4];
489 count = sscanf(line, "P %lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", &width, &height,
490 &values[0], &values[1], &values[2], &values[3],
491 &values[4], &values[5], &values[6], &values[7]);
493 int index = 0;
494 for (int i = 0; i < 4; i++)
495 for (int j = 1; j >= 0; j--)
496 x[i][j] = values[index++];
498 if (count < 10)
499 fprintf(stderr, "\ntrans-load: warning:"
500 "Missing args for 'P'\n");
502 for (i = 0; i < count - 2; i++) {
503 ale_pos factor = (i % 2)
504 ? (result.scaled_width() / width)
505 : (result.scaled_height() / height);
507 x[i / 2][i % 2] *= factor;
510 if (tfile_input_version < 1) {
512 * Accommodate older versions
513 * of tfile.
515 for (i = 0; i < 4; i++) {
516 ale_pos y = x[i][0];
517 x[i][0] = x[i][1];
518 x[i][1] = y;
520 result.gpt_v0_set(x);
521 } else {
522 result.gpt_set(x);
525 return result;
527 break;
528 case 'E':
529 case 'e':
530 /* Euclidean transformation data */
531 *is_default = 0;
533 double width, height;
534 double values[3] = {0, 0, 0};
535 int count, i;
536 ale_pos eu[3];
538 count = sscanf(line, "E %lf%lf%lf%lf%lf",
539 &width, &height,
540 &values[0], &values[1], &values[2]);
542 eu[1] = values[0];
543 eu[0] = values[1];
544 eu[2] = values[2];
546 if (tfile_input_version < 2) {
547 ale_pos t = eu[0];
548 eu[0] = eu[1];
549 eu[1] = t;
553 if (count < 5)
554 fprintf(stderr, "\ntrans-load: warning:"
555 "Missing args for 'E'\n");
557 for (i = 0; (i < count - 2) && (i < 2); i++) {
558 ale_pos factor = (i % 2)
559 ? (result.scaled_width() / width)
560 : (result.scaled_height() / height);
562 eu[i] *= factor;
565 if (tfile_input_version < 1) {
566 result.eu_v0_set(eu);
567 } else {
568 result.eu_set(eu);
571 return result;
573 break;
574 default:
575 fprintf(stderr,
576 "\ntrans-load: Error in tload_next: unrecognized command '%s'\n",
577 line);
578 exit(1);
582 return result;
586 * Create a new tsave_t transformation data file structure, used for
587 * writing data to transformation data files.
590 static inline struct tsave_t *tsave_new(const char *filename) {
591 FILE *file = fopen (filename, "w");
592 struct tsave_t *result = NULL;
594 if (!file) {
595 fprintf(stderr, "tsave: Error: could not open transformation data file '%s'.", filename);
596 exit(1);
599 result = (struct tsave_t *)
600 malloc(sizeof(struct tsave_t));
601 result->filename = filename;
602 result->file = file;
603 result->orig = "unknown";
604 result->target = "unknown";
606 fprintf(file, "# created by ALE transformation file handler version %d\n",
607 TFILE_VERSION);
609 fclose(file);
611 return result;
615 * Save the first transformation to a transformation data file associated with
616 * transformation data file structure T, or do nothing if T is NULL. This
617 * function also establishes the output file version.
619 * OFFSET is the transformation to be saved.
621 * IS_PROJECTIVE indicates whether to write a projective transformation.
625 static inline void tsave_first(struct tsave_t *t, transformation offset, int is_projective) {
627 if (t == NULL)
628 return;
630 t->file = fopen(t->filename, "a");
633 * Determine the output version to use. We use version 3 output syntax only when
634 * necessary. This comprises two cases:
636 * (i) an input file is used, and this file uses version 3 syntax.
637 * (ii) non-degenerate barrel distortion correction is selected.
639 * (i) can be directly examined. When (i) does not hold, (ii) can be
640 * inferred from offset.bd_count(), since this value should be constant
641 * when (i) does not hold. XXX: This logic should be reviewed.
644 if (tfile_input_version == 3 || offset.bd_count() > 0)
645 tfile_output_version = 3;
646 else
647 tfile_output_version = 2;
650 fprintf(t->file, "# producing transformation file syntax version %d\n", tfile_output_version);
651 fprintf(t->file, "V %d\n", tfile_output_version);
653 fprintf(t->file, "# Comment: Target output file is %s\n", t->target);
654 fprintf(t->file, "# Comment: Original frame is %s\n", t->orig);
655 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]);
657 if (tfile_output_version < 3) {
658 fclose(t->file);
659 return;
662 if (offset.bd_count() > 0) {
663 assert (tfile_output_version >= 3);
664 unsigned int i;
666 fprintf(t->file, "B ");
667 fprintf(t->file, "%u ", offset.bd_count());
668 for (i = 0; i < offset.bd_count(); i++)
669 fprintf(t->file, "%f ", (double) offset.bd_get(i));
670 fprintf(t->file, "\n");
674 if (is_projective) {
675 int i, j;
677 fprintf(t->file, "P ");
678 fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
679 for (i = 0; i < 4; i++)
680 for (j = 1; j >= 0; j--)
681 fprintf(t->file, "%f ", (double) offset.gpt_get(i, j));
682 } else {
683 fprintf(t->file, "E ");
684 fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
685 fprintf(t->file, "%f ", (double) offset.eu_get(1));
686 fprintf(t->file, "%f ", (double) offset.eu_get(0));
687 fprintf(t->file, "%f ", (double) offset.eu_get(2));
690 fprintf(t->file, "\n");
692 fclose(t->file);
696 * Save the next transformation to a transformation data file associated with
697 * transformation data file structure T, or do nothing if T is NULL.
699 * OFFSET is the transformation to be saved.
701 * IS_PROJECTIVE indicates whether to write a projective transformation.
705 static inline void tsave_next(struct tsave_t *t, transformation offset, int is_projective) {
707 if (t == NULL)
708 return;
710 t->file = fopen(t->filename, "a");
712 if (offset.bd_count() > 0) {
713 assert (tfile_output_version >= 3);
714 unsigned int i;
716 fprintf(t->file, "B ");
717 fprintf(t->file, "%u ", offset.bd_count());
718 for (i = 0; i < offset.bd_count(); i++)
719 fprintf(t->file, "%f ", (double) offset.bd_get(i));
720 fprintf(t->file, "\n");
723 if (is_projective) {
724 int i, j;
726 fprintf(t->file, "P ");
727 fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
728 for (i = 0; i < 4; i++)
729 for (j = 1; j >= 0; j--)
730 fprintf(t->file, "%f ", (double) offset.gpt_get(i, j));
731 } else {
732 fprintf(t->file, "E ");
733 fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
734 fprintf(t->file, "%f ", (double) offset.eu_get(1));
735 fprintf(t->file, "%f ", (double) offset.eu_get(0));
736 fprintf(t->file, "%f ", (double) offset.eu_get(2));
739 fprintf(t->file, "\n");
741 fclose(t->file);
745 * Write information to a transformation file indicating the target output
746 * file.
749 static inline void tsave_target(struct tsave_t *t, const char *filename) {
750 if (t == NULL)
751 return;
753 t->target = filename;
754 if (t != NULL) {
755 t->file = fopen(t->filename, "a");
758 fclose(t->file);
763 * Write information to a transformation data file indicating the filename
764 * of the original frame (i.e. the first frame in the sequence of input
765 * frames).
768 static inline void tsave_orig(struct tsave_t *t, const char *filename, pixel apm) {
769 if (t == NULL)
770 return;
772 t->orig = filename;
773 t->orig_apm = apm;
777 * Write information to a transformation data file indicating the filename
778 * of a supplemental frame (i.e. a frame in the sequence of input frames
779 * that is not the first frame).
782 static inline void tsave_info(struct tsave_t *t, const char *filename) {
783 if (t != NULL) {
784 t->file = fopen(t->filename, "a");
786 fprintf(t->file, "# Comment: Supplemental frame %s\n", filename);
788 fclose(t->file);
793 * Write information to a transformation data file indicating the tonal
794 * registration multiplier.
797 static inline void tsave_trm(struct tsave_t *t, ale_real r, ale_real g, ale_real b) {
798 if (t != NULL) {
799 t->file = fopen(t->filename, "a");
801 fprintf(t->file, "# Comment: Exposure [r=%f g=%f b=%f]\n", r, g, b);
803 fclose(t->file);
808 * Write information to a transformation data file indicating the average
809 * pixel magnitude.
812 static inline void tsave_apm(struct tsave_t *t, ale_real r, ale_real g, ale_real b) {
813 if (t != NULL) {
814 t->file = fopen(t->filename, "a");
816 fprintf(t->file, "# Comment: Avg magnitude [r=%f g=%f b=%f]\n", r, g, b);
818 fclose(t->file);
824 * Destroy a tload_t transformation data file structure.
827 static inline void tload_delete(struct tload_t *victim) {
828 if (victim)
829 fclose(victim->file);
830 free(victim);
834 * Destroy a tsave_t transformation data file structure.
837 static inline void tsave_delete(struct tsave_t *victim) {
838 free(victim);
841 #endif