Ditz entry for migrating technical documentation.
[Ale.git] / d2 / tfile.h
blob78f2a89b4386a25f95fbc16b1f23e3a66a5057d0
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 char *fgets_result = fgets(line, 1024, t->file);
136 assert(fgets_result);
138 if (strlen(line) >= 1023) {
139 fprintf(stderr,
140 "\ntrans-load: Error: line too long in input file\n");
141 exit(1);
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')
157 * Must be version 0.
160 return result;
163 * Obtain version from version command string.
166 char line[1024];
167 char *fgets_result = fgets(line, 1024, t->file);
169 assert(fgets_result);
171 if (strlen(line) >= 1023) {
172 fprintf(stderr,
173 "\ntrans-load: Error: line too long in input file\n");
174 exit(1);
177 int count = sscanf(line, "V %d", &tfile_input_version);
179 if (count < 1) {
180 fprintf(stderr, "Error in transformation "
181 "file version command.\n");
182 exit(1);
183 } else if (tfile_input_version > TFILE_VERSION_MAX) {
184 fprintf(stderr, "Unsupported transformation "
185 "file version %d\n",
186 tfile_input_version);
187 exit(1);
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.
201 return result;
204 * Read each line of the file until we find a transformation
205 * or EOF.
208 while (!feof(t->file)) {
209 char line[1024];
211 if(!fgets(line, 1024, t->file))
212 return result;
214 if (strlen(line) >= 1023) {
215 fprintf(stderr,
216 "\ntrans-load: Error: line too long in input file\n");
217 exit(1);
220 switch (line[0]) {
221 case ' ':
222 case 0xa:
223 case 0xd:
224 case '\t':
225 case '#':
226 /* Comment or whitespace */
227 break;
228 case 'D':
229 case 'd':
230 /* Default transformation */
231 return result;
232 case 'B':
233 case 'b':
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);
240 exit(1);
241 } else {
242 unsigned int count;
243 unsigned int pos = 0, chars;
244 unsigned int bdc;
245 double dparameters[BARREL_DEGREE];
246 ale_pos parameters[BARREL_DEGREE];
248 count = sscanf(line, "B %u%n", &bdc, &chars);
249 pos += chars;
251 if (count < 1) {
252 fprintf(stderr, "\ntrans-load: Error: "
253 "Malformed 'B' command.\n");
254 exit(1);
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"
261 "trans-load: Hint: "
262 "Reduce degree or re-compile "
263 "with BD_DEGREE=%d\n", bdc, BARREL_DEGREE, bdc);
264 exit(1);
267 for (unsigned int d = 0; d < bdc; d++) {
268 count = sscanf(line + pos, "%lf%n", &dparameters[d], &chars);
269 pos += chars;
271 if (count < 1) {
272 fprintf(stderr, "\ntrans-load: Error: "
273 "Malformed 'B' command.\n");
274 exit(1);
277 parameters[d] = dparameters[d];
280 result.bd_set(bdc, parameters);
282 break;
283 case 'P':
284 case 'p':
285 /* Projective transformation data */
286 *is_default = 0;
287 if (is_p == 0) {
288 fprintf(stderr, "\ntrans-load: Error: "
289 "Projective data for euclidean "
290 "transformation.\n"
291 "trans-load: Hint: "
292 "Use command-line option --projective.\n");
293 exit(1);
294 } else {
295 double width, height, values[8];
296 int count, i;
297 point x[4];
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]);
303 int index = 0;
304 for (int i = 0; i < 4; i++)
305 for (int j = 1; j >= 0; j--)
306 x[i][j] = values[index++];
308 if (count < 10)
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;
320 result.gpt_set(x);
322 return result;
324 break;
325 case 'E':
326 case 'e':
327 /* Euclidean transformation data */
328 *is_default = 0;
330 double width, height;
331 double values[3] = {0, 0, 0};
332 int count, i;
333 ale_pos eu[3];
335 count = sscanf(line + 1, " %lf%lf%lf%lf%lf",
336 &width, &height,
337 &values[0], &values[1], &values[2]);
339 eu[1] = values[0];
340 eu[0] = values[1];
341 eu[2] = values[2];
343 if (count < 5)
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);
352 eu[i] *= factor;
355 result.eu_set(eu);
357 return result;
359 break;
360 default:
361 fprintf(stderr,
362 "\ntrans-load: Error in tload_first: unrecognized command '%s'\n",
363 line);
364 exit(1);
369 * EOF reached: return default transformation.
372 return result;
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
389 * transformations
392 static inline transformation tload_next(struct tload_t *t, int is_p,
393 transformation default_transform, int *is_default,
394 int is_primary) {
396 transformation result = default_transform;
398 *is_default = 1;
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)
408 ungetc(c, t->file);
410 if (feof(t->file)
411 || (!is_primary
412 && c != EOF
413 && (c == 'E'
414 || c == 'e'
415 || c == 'P'
416 || c == 'p'
417 || c == 'D'
418 || c == 'd'
419 || c == 'B'
420 || c == 'b'))) {
421 return result;
424 char line[1024];
426 if (!fgets(line, 1024, t->file))
427 return result;
429 if (strlen(line) >= 1023) {
430 fprintf(stderr,
431 "\ntrans-load: warning: line too long in input file\n");
434 switch (line[0]) {
435 case ' ':
436 case 0xa:
437 case 0xd:
438 case '\t':
439 case '#':
440 /* Comment or whitespace */
441 break;
442 case 'D':
443 case 'd':
444 /* Default transformation */
445 return result;
446 case 'B':
447 case 'b':
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);
454 exit(1);
455 } else {
456 unsigned int count;
457 unsigned int pos = 0, chars;
458 unsigned int bdc;
459 ale_pos parameters[BARREL_DEGREE];
460 double dparameters[BARREL_DEGREE];
462 count = sscanf(line, "B %u%n", &bdc, &chars);
463 pos += chars;
465 if (count < 1) {
466 fprintf(stderr, "\ntrans-load: Error: "
467 "Malformed 'B' command.\n");
468 exit(1);
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"
475 "trans-load: Hint: "
476 "Reduce degree or re-compile "
477 "with BD_DEGREE=%d\n", bdc, BARREL_DEGREE, bdc);
478 exit(1);
481 for (unsigned int d = 0; d < bdc; d++) {
482 count = sscanf(line + pos, "%lf%n", &dparameters[d], &chars);
483 pos += chars;
485 if (count < 1) {
486 fprintf(stderr, "\ntrans-load: Error: "
487 "Malformed 'B' command.\n");
488 exit(1);
491 parameters[d] = dparameters[d];
494 result.bd_set(bdc, parameters);
496 break;
497 case 'Q':
498 case 'q':
499 if (is_primary)
500 break;
501 case 'P':
502 case 'p':
503 /* Projective transformation data */
504 if (is_p == 0) {
505 fprintf(stderr, "\ntrans-load: Error: "
506 "Projective data for euclidean "
507 "transformation.\n"
508 "trans-load: Hint: "
509 "Use command-line option --projective.\n");
510 exit(1);
511 } else {
512 double width, height, values[8];
513 int count, i;
514 point x[4];
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);
522 if (count == 13) {
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))
528 break;
529 if (mc1.degree != mc2.degree
530 || mc1.x != mc2.x
531 || mc1.y != mc2.y) {
532 if (!result.exists(mc1))
533 break;
534 result.set_current_index(result.get_index(mc1));
538 int index = 0;
539 for (int i = 0; i < 4; i++)
540 for (int j = 1; j >= 0; j--)
541 x[i][j] = values[index++];
543 if (count < 10)
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
558 * of tfile.
560 for (i = 0; i < 4; i++) {
561 ale_pos y = x[i][0];
562 x[i][0] = x[i][1];
563 x[i][1] = y;
565 result.gpt_v0_set(x);
566 } else {
567 result.gpt_set(x);
570 *is_default = 0;
571 return result;
573 break;
574 case 'F':
575 case 'f':
576 if (is_primary)
577 break;
578 case 'E':
579 case 'e':
580 /* Euclidean transformation data */
582 double width, height;
583 double values[3] = {0, 0, 0};
584 int count, i;
585 ale_pos eu[3];
586 transformation::multi_coordinate mc1, mc2;
588 count = sscanf(line + 1, " %lf%lf%lf%lf%lf%d%d%d",
589 &width, &height,
590 &values[0], &values[1], &values[2],
591 &mc1.degree, &mc1.x, &mc1.y);
593 if (count == 8) {
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))
599 break;
600 if (mc1.degree != mc2.degree
601 || mc1.x != mc2.x
602 || mc1.y != mc2.y) {
603 if (!result.exists(mc1))
604 break;
605 result.set_current_index(result.get_index(mc1));
610 eu[1] = values[0];
611 eu[0] = values[1];
612 eu[2] = values[2];
614 if (tfile_input_version < 2) {
615 ale_pos t = eu[0];
616 eu[0] = eu[1];
617 eu[1] = t;
621 if (count < 5)
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);
630 eu[i] *= factor;
633 if (tfile_input_version < 1) {
634 result.eu_v0_set(eu);
635 } else {
636 result.eu_set(eu);
639 *is_default = 0;
640 return result;
642 break;
643 default:
644 fprintf(stderr,
645 "\ntrans-load: Error in tload_next: unrecognized command '%s'\n",
646 line);
647 exit(1);
651 return result;
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;
663 if (!file) {
664 fprintf(stderr, "tsave: Error: could not open transformation data file '%s'.", filename);
665 exit(1);
668 result = (struct tsave_t *)
669 malloc(sizeof(struct tsave_t));
670 result->filename = filename;
671 result->file = file;
672 result->orig = "unknown";
673 result->target = "unknown";
675 fprintf(file, "# created by ALE transformation file handler version %d\n",
676 TFILE_VERSION);
678 fclose(file);
680 return result;
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) {
696 if (t == NULL)
697 return;
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;
715 else
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) {
726 fclose(t->file);
727 return;
730 if (offset.bd_count() > 0) {
731 assert (tfile_output_version >= 3);
732 unsigned int i;
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");
742 if (is_projective) {
743 int i, j;
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));
750 } else {
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");
760 fclose(t->file);
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,
776 int is_primary) {
778 if (t == NULL)
779 return;
781 t->file = fopen(t->filename, "a");
783 if (is_primary && offset.bd_count() > 0) {
784 assert (tfile_output_version >= 3);
785 unsigned int i;
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");
794 if (is_projective) {
795 int i, j;
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));
802 } else {
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));
810 if (!is_primary) {
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");
817 fclose(t->file);
821 * Write information to a transformation file indicating the target output
822 * file.
825 static inline void tsave_target(struct tsave_t *t, const char *filename) {
826 if (t == NULL)
827 return;
829 t->target = filename;
830 if (t != NULL) {
831 t->file = fopen(t->filename, "a");
834 fclose(t->file);
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
841 * frames).
844 static inline void tsave_orig(struct tsave_t *t, const char *filename) {
845 if (t == NULL)
846 return;
848 t->orig = 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) {
858 if (t != NULL) {
859 t->file = fopen(t->filename, "a");
861 fprintf(t->file, "# Comment: Supplemental frame %s\n", filename);
863 fclose(t->file);
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) {
873 if (t != NULL) {
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);
878 fclose(t->file);
883 * Destroy a tload_t transformation data file structure.
886 static inline void tload_delete(struct tload_t *victim) {
887 if (victim)
888 fclose(victim->file);
889 free(victim);
893 * Destroy a tsave_t transformation data file structure.
896 static inline void tsave_delete(struct tsave_t *victim) {
897 free(victim);
900 #endif