d2::align: Change allocation and deallocation of LOD structures so that 0-level certa...
[Ale.git] / d2 / tfile.h
blob5e02bcb8cb9fed32e14c2b2907d0031e24aa90e7
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 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 + 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]);
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 + 1, " %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.
385 * IS_PRIMARY is used to differentiate primary and non-primary
386 * transformations
389 static inline transformation tload_next(struct tload_t *t, int is_p,
390 transformation default_transform, int *is_default,
391 int is_primary) {
393 transformation result = default_transform;
395 *is_default = 1;
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)
405 ungetc(c, t->file);
407 if (feof(t->file)
408 || (!is_primary
409 && c != EOF
410 && (c == 'E'
411 || c == 'e'
412 || c == 'P'
413 || c == 'p'
414 || c == 'D'
415 || c == 'd'
416 || c == 'B'
417 || c == 'b'))) {
418 return result;
421 char line[1024];
423 fgets(line, 1024, t->file);
425 if (feof(t->file))
426 return result;
428 if (strlen(line) >= 1023) {
429 fprintf(stderr,
430 "\ntrans-load: warning: line too long in input file\n");
433 switch (line[0]) {
434 case ' ':
435 case 0xa:
436 case 0xd:
437 case '\t':
438 case '#':
439 /* Comment or whitespace */
440 break;
441 case 'D':
442 case 'd':
443 /* Default transformation */
444 return result;
445 case 'B':
446 case 'b':
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);
453 exit(1);
454 } else {
455 unsigned int count;
456 unsigned int pos = 0, chars;
457 unsigned int bdc;
458 ale_pos parameters[BARREL_DEGREE];
459 double dparameters[BARREL_DEGREE];
461 count = sscanf(line, "B %u%n", &bdc, &chars);
462 pos += chars;
464 if (count < 1) {
465 fprintf(stderr, "\ntrans-load: Error: "
466 "Malformed 'B' command.\n");
467 exit(1);
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"
474 "trans-load: Hint: "
475 "Reduce degree or re-compile "
476 "with BD_DEGREE=%d\n", bdc, BARREL_DEGREE, bdc);
477 exit(1);
480 for (unsigned int d = 0; d < bdc; d++) {
481 count = sscanf(line + pos, "%lf%n", &dparameters[d], &chars);
482 pos += chars;
484 if (count < 1) {
485 fprintf(stderr, "\ntrans-load: Error: "
486 "Malformed 'B' command.\n");
487 exit(1);
490 parameters[d] = dparameters[d];
493 result.bd_set(bdc, parameters);
495 break;
496 case 'Q':
497 case 'q':
498 if (is_primary)
499 break;
500 case 'P':
501 case 'p':
502 /* Projective transformation data */
503 *is_default = 0;
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];
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]);
520 int index = 0;
521 for (int i = 0; i < 4; i++)
522 for (int j = 1; j >= 0; j--)
523 x[i][j] = values[index++];
525 if (count < 10)
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
540 * of tfile.
542 for (i = 0; i < 4; i++) {
543 ale_pos y = x[i][0];
544 x[i][0] = x[i][1];
545 x[i][1] = y;
547 result.gpt_v0_set(x);
548 } else {
549 result.gpt_set(x);
552 return result;
554 break;
555 case 'F':
556 case 'f':
557 if (is_primary)
558 break;
559 case 'E':
560 case 'e':
561 /* Euclidean transformation data */
562 *is_default = 0;
564 double width, height;
565 double values[3] = {0, 0, 0};
566 int count, i;
567 ale_pos eu[3];
569 count = sscanf(line + 1, " %lf%lf%lf%lf%lf",
570 &width, &height,
571 &values[0], &values[1], &values[2]);
573 eu[1] = values[0];
574 eu[0] = values[1];
575 eu[2] = values[2];
577 if (tfile_input_version < 2) {
578 ale_pos t = eu[0];
579 eu[0] = eu[1];
580 eu[1] = t;
584 if (count < 5)
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);
593 eu[i] *= factor;
596 if (tfile_input_version < 1) {
597 result.eu_v0_set(eu);
598 } else {
599 result.eu_set(eu);
602 return result;
604 break;
605 default:
606 fprintf(stderr,
607 "\ntrans-load: Error in tload_next: unrecognized command '%s'\n",
608 line);
609 exit(1);
613 return result;
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;
625 if (!file) {
626 fprintf(stderr, "tsave: Error: could not open transformation data file '%s'.", filename);
627 exit(1);
630 result = (struct tsave_t *)
631 malloc(sizeof(struct tsave_t));
632 result->filename = filename;
633 result->file = file;
634 result->orig = "unknown";
635 result->target = "unknown";
637 fprintf(file, "# created by ALE transformation file handler version %d\n",
638 TFILE_VERSION);
640 fclose(file);
642 return result;
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) {
658 if (t == NULL)
659 return;
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;
677 else
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) {
689 fclose(t->file);
690 return;
693 if (offset.bd_count() > 0) {
694 assert (tfile_output_version >= 3);
695 unsigned int i;
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");
705 if (is_projective) {
706 int i, j;
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));
713 } else {
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");
723 fclose(t->file);
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,
739 int is_primary) {
741 if (t == NULL)
742 return;
744 t->file = fopen(t->filename, "a");
746 if (is_primary && offset.bd_count() > 0) {
747 assert (tfile_output_version >= 3);
748 unsigned int i;
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");
757 if (is_projective) {
758 int i, j;
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));
765 } else {
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");
775 fclose(t->file);
779 * Write information to a transformation file indicating the target output
780 * file.
783 static inline void tsave_target(struct tsave_t *t, const char *filename) {
784 if (t == NULL)
785 return;
787 t->target = filename;
788 if (t != NULL) {
789 t->file = fopen(t->filename, "a");
792 fclose(t->file);
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
799 * frames).
802 static inline void tsave_orig(struct tsave_t *t, const char *filename, pixel apm) {
803 if (t == NULL)
804 return;
806 t->orig = filename;
807 t->orig_apm = 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) {
817 if (t != NULL) {
818 t->file = fopen(t->filename, "a");
820 fprintf(t->file, "# Comment: Supplemental frame %s\n", filename);
822 fclose(t->file);
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) {
832 if (t != NULL) {
833 t->file = fopen(t->filename, "a");
835 fprintf(t->file, "# Comment: Exposure [r=%f g=%f b=%f]\n", r, g, b);
837 fclose(t->file);
842 * Write information to a transformation data file indicating the average
843 * pixel magnitude.
846 static inline void tsave_apm(struct tsave_t *t, ale_real r, ale_real g, ale_real b) {
847 if (t != NULL) {
848 t->file = fopen(t->filename, "a");
850 fprintf(t->file, "# Comment: Avg magnitude [r=%f g=%f b=%f]\n", r, g, b);
852 fclose(t->file);
858 * Destroy a tload_t transformation data file structure.
861 static inline void tload_delete(struct tload_t *victim) {
862 if (victim)
863 fclose(victim->file);
864 free(victim);
868 * Destroy a tsave_t transformation data file structure.
871 static inline void tsave_delete(struct tsave_t *victim) {
872 free(victim);
875 #endif