d2/align, d2/image_rw: Revise migration-related messages to use pre-processor warnings.
[Ale.git] / d2 / image_rw.h
blob1ab7221ce42073927cd6a9d4a5f9760677bc414f
1 // Copyright 2002 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 * image_rw.h: Read and write images.
26 #ifndef __image_rw_h__
27 #define __image_rw_h__
29 #include "image.h"
30 #include "image_ale_real.h"
31 #include "image_bayer_ale_real.h"
32 #include "image_accel.h"
33 #include "ppm.h"
34 #include "exposure/exposure.h"
35 #include "exposure/exposure_default.h"
37 class image_rw {
40 * Private data members
44 * PPM type
46 * 0 = No type selected
47 * 1 = PPM Raw
48 * 2 = PPM Plain
50 static int ppm_type;
53 * Bit depth
55 static unsigned int num_bits;
56 static unsigned int mcv;
59 * Nearest-neighbor defined value radius.
61 static double nn_defined_radius;
64 * Input and output exposure models
66 static exposure **input_exposure;
67 static exposure *output_exposure;
68 static int exposure_scale;
71 * Default bayer pattern
73 static unsigned int bayer_default;
76 * Image-specific bayer patterns.
78 static unsigned int *bayer_specific;
81 * Pointer to the output filename
83 static const char *output_filename;
86 * Variables relating to input image files and image data structures.
88 static const char **filenames;
89 static unsigned int file_count;
90 static ale_image *images;
91 static int *files_open;
94 * The most recently closed image number.
96 static int latest_close_num;
99 * Actual cache size.
101 static double cache_size;
104 * Number of cached files.
106 static unsigned int cache_count;
109 * Private methods to init and shut down the file reader.
113 * Initialize the image file handler
115 static void init_image() {
116 #ifdef USE_MAGICK
117 InitializeMagick("ale");
118 #endif
122 * Destroy the image file handler
124 static void destroy_image() {
125 #ifdef USE_MAGICK
126 DestroyMagick();
127 #endif
130 static ale_image read_image_im(const char *filename, exposure *exp, const char *name,
131 unsigned int bayer, int init_reference_gain) {
132 static int warned = 0;
133 #ifdef USE_MAGICK
135 if (MaxRGB < 65535 && mcv == 65535 && !warned) {
136 fprintf(stderr, "\n\n*** Warning: " MagickPackageName " has not been compiled with 16 bit support.\n");
137 fprintf(stderr, "*** Reading input using 8 bits per channel.\n");
138 fprintf(stderr, "*** \n");
139 fprintf(stderr, "*** (To silence this warning, specify option --8bpc)\n\n\n");
141 warned = 1;
145 * Patterned after http://www.imagemagick.org/www/api.html
146 * and http://www.imagemagick.org/www/smile.c
149 ExceptionInfo exception;
150 Image *mi;
151 ImageInfo *image_info;
152 ale_image im;
153 FILE *converted_f = tmpfile();
154 const PixelPacket *p;
156 unsigned int i, j;
158 ale_real black_level = exp->get_black_level();
160 GetExceptionInfo(&exception);
161 image_info = CloneImageInfo((ImageInfo *) NULL);
163 strncpy(image_info->filename, filename, MaxTextExtent);
164 mi = ReadImage(image_info, &exception);
165 if (exception.severity != UndefinedException) {
166 fprintf(stderr, "\n\n");
167 CatchException(&exception);
168 fprintf(stderr, "\n");
170 if (mi == (Image *) NULL)
171 exit(1);
173 im = ale_new_image(accel::context(),
174 (bayer == IMAGE_BAYER_NONE) ? ALE_IMAGE_RGB : ALE_IMAGE_Y,
175 (image_info->depth == 8) ? ALE_TYPE_UINT_8 :
176 ((image_info->depth == 16) ? ALE_TYPE_UINT_16 :
177 ((image_info->depth == 32) ? ALE_TYPE_UINT_32 : ALE_TYPE_UINT_64)));
179 for (i = 0; i < mi->rows; i++) {
180 p = AcquireImagePixels(mi, 0, i, mi->columns, 1, &exception);
182 if (exception.severity != UndefinedException)
183 CatchException(&exception);
184 if (p == NULL)
185 exit(1);
187 for (j = 0; j < mi->columns; j++) {
189 long ival[3] = { p->red, p->green, p->blue };
191 for (int k = 0; k < 3; k++) {
193 if (!ale_has_channel(i, j, k, bayer))
194 continue;
196 fprintf(converted_f, "%c", ((char *) ival)[0]);
197 if (image_info->depth >= 16)
198 fprintf(converted_f, "%c", ((char *) ival)[1]);
199 if (image_info->depth >= 32)
200 fprintf(converted_f, "%c%c", ((char *) ival)[2], ((char *) ival)[3]);
201 if (image_info->depth >= 64)
202 fprintf(converted_f, "%c%c%c%c", ((char *) ival)[4], ((char *) ival)[5], ((char *) ival)[6], ((char *) ival)[7]); // XXX: ival might be too short for this
206 p++;
210 ale_image_set_file_static(im, mi->columns, mi->rows, converted_f, 0, ppm_void_file_close, converted_f);
212 DestroyImage(mi);
213 DestroyImageInfo(image_info);
215 return im;
216 #else
217 return NULL;
218 #endif
221 public:
224 * Read an image from a file
226 static ale_image read_image(const char *filename, exposure *exp, const char *name = "file",
227 unsigned int bayer = IMAGE_BAYER_DEFAULT, int init_reference_gain = 0) {
228 ale_image result;
230 if (bayer == IMAGE_BAYER_DEFAULT)
231 bayer = bayer_default;
233 if (is_eppm(filename)) {
234 result = read_ppm(filename, exp, bayer, init_reference_gain);
237 #ifdef USE_MAGICK
238 result = read_image_im(filename, exp, name, bayer, init_reference_gain);
239 #else
240 result = read_ppm(filename, exp, bayer);
241 #endif
243 return result;
247 * Initializer.
249 * Handle FILE_COUNT input files with names in array FILENAMES and
250 * output file OUTPUT_FILENAME. FILENAMES should be an array of char *
251 * that is never freed. OUTPUT_FILENAME should be a char * that is
252 * never freed.
254 * INPUT_EXPOSURE should be an array of FILE_COUNT exposure objects
255 * that is never freed. OUTPUT_EXPOSURE should be an exposure * that
256 * is never freed.
258 static void init(unsigned int _file_count, const char **_filenames,
259 const char *_output_filename, exposure **_input_exposure,
260 exposure *_output_exposure){
261 assert (_file_count > 0);
263 init_image();
265 filenames = _filenames;
266 file_count = _file_count;
267 output_filename = _output_filename;
268 input_exposure = _input_exposure;
269 output_exposure = _output_exposure;
271 images = (ale_image *)malloc(file_count * sizeof(ale_image));
272 bayer_specific = (unsigned int *)malloc(file_count * sizeof(unsigned int));
273 files_open = (int *)calloc(file_count, sizeof(int));
275 assert (images);
276 assert (bayer_specific);
277 assert (files_open);
279 if (!images || !files_open || !bayer_specific) {
280 fprintf(stderr, "Unable to allocate memory for images.\n");
281 exit(1);
284 for (unsigned int i = 0; i < file_count; i++)
285 bayer_specific[i] = IMAGE_BAYER_DEFAULT;
287 ui::get()->identify_output(output_filename);
290 static void ppm_plain() {
291 ppm_type = 2;
294 static void ppm_raw() {
295 ppm_type = 1;
298 static void ppm_auto() {
299 #ifdef USE_MAGICK
300 ppm_type = 0;
301 #else
302 fprintf(stderr, "\n\n*** Error: --auto flag not supported on this build. ***\n"
303 "*** (Hint: Rebuild with IMAGEMAGICK=1) ***\n\n");
304 exit(1);
305 #endif
308 static void set_default_bayer(unsigned int b) {
309 bayer_default = b;
312 static void set_specific_bayer(unsigned int index, unsigned int b) {
313 assert (bayer_specific);
314 bayer_specific[index] = b;
317 static void depth16() {
318 num_bits = 16;
319 mcv = 65535;
322 static void depth8() {
323 num_bits = 8;
324 mcv = 255;
327 static void destroy() {
328 assert (file_count > 0);
329 destroy_image();
332 static unsigned int count() {
333 assert (file_count > 0);
334 return file_count;
337 static const char *name(unsigned int image) {
338 assert (image < file_count);
340 return filenames[image];
343 static void def_nn(double _nn) {
344 nn_defined_radius = _nn;
347 static const char *output_name() {
348 assert (file_count > 0);
349 return output_filename;
353 * Write an image to a file
355 static void write_image(const char *filename, ale_image im, int rezero = 0, int exp_scale_override = 0, double gamma = 0.45) {
356 static int warned = 0;
359 * Handle ALE-specific magical filenames.
362 if (!strcmp(filename, "dump:")) {
363 FILE *image_data = ale_image_retain_file(im);
365 int format = ale_image_get_format(im);
366 int type = ale_image_get_type(im);
368 fprintf(stderr, "Image dump: ");
369 for (unsigned int i = 0; i < ale_image_get_height(im); i++)
370 for (unsigned int j = 0; j < ale_image_get_width(im); j++) {
371 fprintf(stderr, "(%d, %d): ", i, j);
373 fprintf(stderr, "[");
375 for (unsigned int k = 0; k < ale_image_get_depth(im); k++) {
377 unsigned char data[8];
379 if (k != 0)
380 fprintf(stderr, " ");
382 switch (type) {
383 ALE_TYPE_UINT_8:
384 fscanf(image_data, "%c", &data[0]);
385 fprintf(stderr, "%u", (unsigned int) data[0]);
386 break;
387 ALE_TYPE_UINT_16:
388 fscanf(image_data, "%c%c", &data[0], &data[1]);
389 fprintf(stderr, "%u", (unsigned int) *((unsigned short *) data));
390 break;
391 ALE_TYPE_UINT_32:
392 fscanf(image_data, "%c%c%c%c", &data[0], &data[1], &data[2], &data[3]);
393 fprintf(stderr, "%u", *((unsigned int *) data));
394 break;
395 ALE_TYPE_UINT_64:
396 fscanf(image_data, "%c%c%c%c%c%c%c%c", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], &data[7]);
397 fprintf(stderr, "%lu", *((unsigned long *) data)); // XXX: may not be long enough.
398 break;
399 ALE_TYPE_FLOAT_32:
400 fscanf(image_data, "%c%c%c%c", &data[0], &data[1], &data[2], &data[3]);
401 fprintf(stderr, "%f", (double) *((float *) data));
402 break;
403 ALE_TYPE_FLOAT_64:
404 fscanf(image_data, "%c%c%c%c%c%c%c%c", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], &data[7]);
405 fprintf(stderr, "%f", *((double *) data));
406 break;
409 fprintf(stderr, "] ");
411 fprintf(stderr, "\n");
413 ale_image_release_file(im, image_data);
415 return;
418 #ifdef USE_MAGICK
420 * If necessary, adjust mcv to match library limits.
423 if (MaxRGB < 65535 && mcv == 65535) {
424 fprintf(stderr, "\n\n*** Warning: " MagickPackageName " has not been compiled with 16 bit support.\n");
425 fprintf(stderr, "*** Writing output using 8 bits per channel.\n");
426 fprintf(stderr, "*** \n");
427 fprintf(stderr, "*** (To silence this warning, specify option --8bpc)\n\n\n");
429 mcv = 255;
431 #endif
434 * Automatic exposure adjustment (don't blow out highlights)
436 ale_real maxval = 1;
437 ale_real minval = (rezero ? (ale_real) ale_image_minval(im) : (ale_real) 0);
438 if (minval > 0)
439 minval = 0;
440 pixel minval_pixel(minval, minval, minval);
443 if (exposure_scale || exp_scale_override) {
444 ale_real new_maxval = ale_image_maxval(im);
446 if (new_maxval > maxval)
447 maxval = new_maxval;
451 * Nearest-neighbor fill.
454 ale_image temp_image = ale_image_nn_fill(im, nn_defined_radius);
457 * Unlinearize
460 ale_image_map_1(temp_image, temp_image, "\
461 SET_PIXEL(p, pow((GET_PIXEL(0, p) - (PIXEL(1, 1, 1) * %0f)) / (%1f - %0f), %2f))",
462 minval, maxval, gamma);
464 #ifdef USE_MAGICK
467 * Patterned after http://www.imagemagick.org/www/api.html
468 * and http://www.imagemagick.org/www/smile.c
471 ExceptionInfo exception;
472 Image *mi;
473 ImageInfo *image_info;
474 PixelPacket *p;
476 unsigned int i, j;
478 GetExceptionInfo(&exception);
479 image_info = CloneImageInfo((ImageInfo *) NULL);
480 strncpy(image_info->filename, filename, MaxTextExtent);
482 mi = AllocateImage(image_info);
483 if (mi == (Image *) NULL)
484 MagickError(ResourceLimitError,
485 "Unable to display image", "MemoryAllocationFailed");
487 mi->columns = ale_image_get_width(im);
488 mi->rows = ale_image_get_height(im);
491 * Set the output image depth
494 if (mcv < 65535)
495 mi->depth = 8;
496 else
497 mi->depth = 16;
500 * Set compression type
503 if (ppm_type == 2) {
504 mi->compression = NoCompression;
505 image_info->compression = NoCompression;
506 strncpy(mi->magick, "PNM", MaxTextExtent);
507 strncpy(image_info->magick, "PNM", MaxTextExtent);
508 } else if (ppm_type == 1) {
509 strncpy(mi->magick, "PNM", MaxTextExtent);
510 strncpy(image_info->magick, "PNM", MaxTextExtent);
514 * Write the image
517 FILE *image_data = ale_image_retain_file(temp_image);
519 for (i = 0; i < mi->rows; i++) {
520 p = SetImagePixels(mi, 0, i, mi->columns, 1);
521 if (p == NULL)
522 break;
524 for (j = 0; j < mi->columns; j++) {
526 pixel value = im->get_pixel(i, j);
528 #warning migrate to libale
529 #if 0
531 * Get nearest-neighbor defined values.
533 * XXX: While this implementation is correct, it is inefficient
534 * for large radii. A better implementation would search
535 * perimeters of squares of ever-increasing radius, tracking
536 * the best-so-far data until the square perimeter exceeded the
537 * best-so-far radius.
540 for (int k = 0; k < 3; k++)
541 if (isnan(value[k]))
542 for (int radius = 1; radius <= nn_defined_radius; radius++) {
543 double nearest_radius_squared = (radius + 1) * (radius + 1);
544 for (int ii = -radius; ii <= radius; ii++)
545 for (int jj = -radius; jj <= radius; jj++) {
546 if (!im->in_bounds(point(i + ii, j + jj)))
547 continue;
548 if (ii * ii + jj * jj < nearest_radius_squared
549 && finite(im->get_pixel(i + ii, j + jj)[k])) {
550 value[k] = im->get_pixel(i + ii, j + jj)[k];
551 nearest_radius_squared = ii * ii + jj * jj;
554 if (nearest_radius_squared < (radius + 1) * (radius + 1))
555 break;
559 * Unlinearize
562 pixel unlinearized(exp->unlinearize((value - minval_pixel)
563 / (maxval - minval)));
565 unlinearized = unlinearized.clamp();
566 #endif
568 p->red = (Quantum) ale_real_to_int(unlinearized[0], MaxRGB);
569 p->green = (Quantum) ale_real_to_int(unlinearized[1], MaxRGB);
570 p->blue = (Quantum) ale_real_to_int(unlinearized[2], MaxRGB);
571 p++;
574 if (!SyncImagePixels(mi))
575 break;
578 ale_image_release_file(temp_image, image_data);
580 if (!WriteImage(image_info, mi)) {
583 * Perhaps file type was unknown? Set to PNM by default.
586 strncpy(mi->magick, "PNM", MaxTextExtent);
587 strncpy(image_info->magick, "PNM", MaxTextExtent);
589 if (!WriteImage(image_info, mi)) {
590 fprintf(stderr, "\n\n");
591 CatchException(&mi->exception);
592 fprintf(stderr, "\n");
593 exit(1);
597 DestroyImage(mi);
598 DestroyImageInfo(image_info);
599 #else
600 write_ppm(filename, temp_image, mcv, ppm_type == 2);
601 #endif
603 ale_image_release(temp_image);
608 static void output(const image *i) {
609 assert (file_count > 0);
610 write_image(output_name(), i, output_exposure);
613 static void vise_write(const char *p, const char *s, const image *i) {
614 static int count = 0;
615 int length = strlen(p) + strlen(s) + 8;
616 char *output_string = (char *) malloc(length * sizeof(char));
618 snprintf(output_string, length, "%s%08d%s", p, count, s);
620 write_image(output_string, i, output_exposure);
622 count++;
625 static exposure &exp(int n) {
626 return *input_exposure[n];
629 static const exposure &const_exp(int n) {
630 return *input_exposure[n];
633 static exposure &exp() {
634 return *output_exposure;
637 static void exp_scale() {
638 exposure_scale = 1;
641 static void exp_noscale() {
642 exposure_scale = 0;
645 static const exposure &const_exp() {
646 return *output_exposure;
649 static const unsigned int bayer(unsigned int n) {
650 if (bayer_specific[n] == IMAGE_BAYER_DEFAULT)
651 return bayer_default;
652 else
653 return bayer_specific[n];
656 static const ale_image open_simple(unsigned int n) {
657 assert (n < file_count);
659 return read_image(filenames[n], input_exposure[n], "file", bayer(n), (n == 0));
662 static const ale_image open(unsigned int n) {
663 assert (n < file_count);
664 assert (!files_open[n]);
666 files_open[n] = 1;
668 if (latest_close_num >= 0 && n == (unsigned int) latest_close_num) {
669 latest_close_num = -1;
670 return images[n];
673 if (n < cache_count)
674 return images[n];
676 ui::get()->loading_file();
677 ale_image i = read_image(filenames[n], input_exposure[n], "file", bayer(n), (n == 0));
679 images[n] = i;
681 return images[n];
684 static void open_all() {
685 for (unsigned int n = 0; n < file_count; n++)
686 open(n);
689 static ale_image get_open(unsigned int n) {
690 assert (files_open[n]);
691 return images[n];
694 #if 0
696 * XXX: as far as I can tell, 'copy' is currently always used
697 * as a kind of 'retain', so that calls to this can probably be
698 * replaced by calls to an appropriate retain method.
701 static ale_image copy(unsigned int n, const char *name) {
702 assert (n < file_count);
704 if (files_open[n])
705 return images[n]->clone(name);
706 else {
707 image *i = read_image(filenames[n], input_exposure[n], name, bayer(n), (n == 0));
708 return i;
711 #endif
713 #if 0
715 * This method should be replaced by ale_sequence_release_image.
718 static void close(unsigned int image) {
719 assert (image < file_count);
720 assert (files_open[image]);
722 files_open[image] = 0;
724 if (image < cache_count)
725 return;
727 if (image == cache_count) {
728 double image_size = ((double) images[image]->storage_size()) / pow(2, 20);
730 if (image_size + cache_size < cache_size_max) {
731 cache_size += image_size;
732 cache_count++;
733 ui::get()->cache(cache_size, cache_size_max);
734 return;
735 } else {
736 ui::get()->cache_status(0);
740 if (latest_close_num >= 0)
741 delete images[latest_close_num];
743 latest_close_num = image;
746 static void close_all() {
747 for (unsigned int n = 0; n < file_count; n++)
748 close(n);
750 #endif
754 #endif