doc/Makefile: add code outlining table of contents parameters.
[Ale.git] / d2 / image_rw.h
blob0c3aa0e69cd91cde04abadbaaf5a0c4009185ff2
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 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 * 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 "ppm.h"
33 #include "exposure/exposure.h"
34 #include "exposure/exposure_default.h"
36 class image_rw {
39 * Private data members
43 * PPM type
45 * 0 = No type selected
46 * 1 = PPM Raw
47 * 2 = PPM Plain
49 static int ppm_type;
52 * Bit depth
54 static unsigned int num_bits;
55 static unsigned int mcv;
58 * Nearest-neighbor defined value radius.
60 static double nn_defined_radius;
63 * Input and output exposure models
65 static exposure **input_exposure;
66 static exposure *output_exposure;
67 static int exposure_scale;
70 * Default bayer pattern
72 static unsigned int bayer_default;
75 * Image-specific bayer patterns.
77 static unsigned int *bayer_specific;
80 * Pointer to the output filename
82 static const char *output_filename;
85 * Variables relating to input image files and image data structures.
87 static const char **filenames;
88 static unsigned int file_count;
89 static const image **images;
90 static int *files_open;
93 * The most recently closed image number.
95 static int latest_close_num;
98 * A cache of the data associated with the most recently closed image.
100 static const image *latest_close;
103 * Private methods to init and shut down the file reader.
107 * Initialize the image file handler
109 static void init_image() {
110 #ifdef USE_MAGICK
111 InitializeMagick("ale");
112 #endif
116 * Destroy the image file handler
118 static void destroy_image() {
119 #ifdef USE_MAGICK
120 DestroyMagick();
121 #endif
124 public:
127 * Methods to read and write image files
131 * Read an image from a file
133 static image *read_image(const char *filename, exposure *exp, char *name = "file",
134 unsigned int bayer = IMAGE_BAYER_DEFAULT, int init_reference_gain = 0) {
135 if (bayer == IMAGE_BAYER_DEFAULT)
136 bayer = bayer_default;
138 if (is_eppm(filename)) {
139 return read_ppm(filename, exp, bayer, init_reference_gain);
142 #ifdef USE_MAGICK
144 * Patterned after http://www.imagemagick.org/www/api.html
145 * and http://www.imagemagick.org/www/smile.c
148 ExceptionInfo exception;
149 Image *mi;
150 ImageInfo *image_info;
151 image *im;
152 const PixelPacket *p;
154 unsigned int i, j;
156 GetExceptionInfo(&exception);
157 image_info = CloneImageInfo((ImageInfo *) NULL);
159 strncpy(image_info->filename, filename, MaxTextExtent);
160 mi = ReadImage(image_info, &exception);
161 if (exception.severity != UndefinedException) {
162 fprintf(stderr, "\n\n");
163 CatchException(&exception);
164 fprintf(stderr, "\n");
166 if (mi == (Image *) NULL)
167 exit(1);
169 if (bayer == IMAGE_BAYER_NONE)
170 im = new image_ale_real(mi->rows, mi->columns, 3, name, exp);
171 else
172 im = new image_bayer_ale_real(mi->rows, mi->columns, 3, bayer, name, exp);
174 for (i = 0; i < mi->rows; i++) {
175 p = AcquireImagePixels(mi, 0, i, mi->columns, 1, &exception);
177 if (exception.severity != UndefinedException)
178 CatchException(&exception);
179 if (p == NULL)
180 exit(1);
182 for (j = 0; j < mi->columns; j++) {
183 pixel input( (ale_real) p->red / MaxRGB,
184 (ale_real) p->green / MaxRGB,
185 (ale_real) p->blue / MaxRGB );
187 im->set_pixel(i, j, exp->linearize(input));
189 p++;
193 DestroyImage(mi);
194 DestroyImageInfo(image_info);
196 return im;
197 #else
198 return read_ppm(filename, exp, bayer);
199 #endif
203 * Initializer.
205 * Handle FILE_COUNT input files with names in array FILENAMES and
206 * output file OUTPUT_FILENAME. FILENAMES should be an array of char *
207 * that is never freed. OUTPUT_FILENAME should be a char * that is
208 * never freed.
210 * INPUT_EXPOSURE should be an array of FILE_COUNT exposure objects
211 * that is never freed. OUTPUT_EXPOSURE should be an exposure * that
212 * is never freed.
214 static void init(unsigned int _file_count, const char **_filenames,
215 const char *_output_filename, exposure **_input_exposure,
216 exposure *_output_exposure){
217 assert (_file_count > 0);
219 init_image();
221 filenames = _filenames;
222 file_count = _file_count;
223 output_filename = _output_filename;
224 input_exposure = _input_exposure;
225 output_exposure = _output_exposure;
227 images = (const image **)malloc(file_count * sizeof(image *));
228 bayer_specific = (unsigned int *)malloc(file_count * sizeof(unsigned int));
229 files_open = (int *)calloc(file_count, sizeof(int));
231 assert (images);
232 assert (bayer_specific);
233 assert (files_open);
235 if (!images || !files_open || !bayer_specific) {
236 fprintf(stderr, "Unable to allocate memory for images.\n");
237 exit(1);
240 for (unsigned int i = 0; i < file_count; i++)
241 bayer_specific[i] = IMAGE_BAYER_DEFAULT;
243 fprintf(stderr, "Output file will be '%s'.\n",
244 output_filename);
248 static void ppm_plain() {
249 ppm_type = 2;
252 static void ppm_raw() {
253 ppm_type = 1;
256 static void ppm_auto() {
257 #ifdef USE_MAGICK
258 ppm_type = 0;
259 #else
260 fprintf(stderr, "\n\n*** Error: --auto flag not supported on this build. ***\n"
261 "*** (Hint: Rebuild with IMAGEMAGICK=1) ***\n\n");
262 exit(1);
263 #endif
266 static void set_default_bayer(unsigned int b) {
267 bayer_default = b;
270 static void set_specific_bayer(unsigned int index, unsigned int b) {
271 assert (bayer_specific);
272 bayer_specific[index] = b;
275 static void depth16() {
276 num_bits = 16;
277 mcv = 65535;
280 static void depth8() {
281 num_bits = 8;
282 mcv = 255;
285 static void destroy() {
286 assert (file_count > 0);
287 destroy_image();
290 static unsigned int count() {
291 assert (file_count > 0);
292 return file_count;
295 static const char *name(unsigned int image) {
296 assert (image < file_count);
298 return filenames[image];
301 static void def_nn(double _nn) {
302 nn_defined_radius = _nn;
305 static const char *output_name() {
306 assert (file_count > 0);
307 return output_filename;
311 * Write an image to a file
313 static void write_image(const char *filename, const image *im, exposure *exp = output_exposure, int rezero = 0, int exp_scale_override = 0) {
315 * Handle ALE-specific magical filenames.
318 if (!strcmp(filename, "dump:")) {
319 fprintf(stderr, "Image dump: ");
320 for (unsigned int i = 0; i < im->height(); i++)
321 for (unsigned int j = 0; j < im->width(); j++) {
322 pixel p = im->pix(i, j);
323 fprintf(stderr, "(%d, %d): [%f %f %f] ", i, j, p[0], p[1], p[2]);
325 fprintf(stderr, "\n");
327 return;
330 #ifdef USE_MAGICK
333 * Patterned after http://www.imagemagick.org/www/api.html
334 * and http://www.imagemagick.org/www/smile.c
337 ExceptionInfo exception;
338 Image *mi;
339 ImageInfo *image_info;
340 PixelPacket *p;
342 unsigned int i, j;
344 GetExceptionInfo(&exception);
345 image_info = CloneImageInfo((ImageInfo *) NULL);
346 strncpy(image_info->filename, filename, MaxTextExtent);
348 mi = AllocateImage(image_info);
349 if (mi == (Image *) NULL)
350 MagickError(ResourceLimitError,
351 "Unable to display image", "MemoryAllocationFailed");
353 mi->columns = im->width();
354 mi->rows = im->height();
357 * Set the output image depth
360 if (MaxRGB < 65535 || mcv < 65535)
361 mi->depth = 8;
362 else
363 mi->depth = 16;
365 if (MaxRGB < 65535 && mcv == 65535) {
366 fprintf(stderr, "\n\n*** Warning: 16 bit-per-channel file output was specified,\n");
367 fprintf(stderr, "*** but ImageMagick has not been compiled with support for this.\n");
368 fprintf(stderr, "*** Writing output using 8 bits per channel.\n");
372 * Set compression type
375 if (ppm_type == 2) {
376 mi->compression = NoCompression;
377 image_info->compression = NoCompression;
378 strncpy(mi->magick, "PNM", MaxTextExtent);
379 strncpy(image_info->magick, "PNM", MaxTextExtent);
380 } else if (ppm_type == 1) {
381 strncpy(mi->magick, "PNM", MaxTextExtent);
382 strncpy(image_info->magick, "PNM", MaxTextExtent);
386 * Automatic exposure adjustment (don't blow out highlights)
388 ale_real maxval = 1;
389 ale_real minval = (rezero ? im->minval() : 0);
390 if (minval > 0)
391 minval = 0;
392 pixel minval_pixel(minval, minval, minval);
395 if (exposure_scale || exp_scale_override) {
396 ale_real new_maxval = im->maxval();
398 if (new_maxval > maxval)
399 maxval = new_maxval;
403 * Write the image
406 for (i = 0; i < mi->rows; i++) {
407 p = SetImagePixels(mi, 0, i, mi->columns, 1);
408 if (p == NULL)
409 break;
411 for (j = 0; j < mi->columns; j++) {
413 pixel value = im->get_pixel(i, j);
416 * Get nearest-neighbor defined values.
418 * XXX: While this implementation is correct, it is inefficient
419 * for large radii. A better implementation would search
420 * perimeters of squares of ever-increasing radius, tracking
421 * the best-so-far data until the square perimeter exceeded the
422 * best-so-far radius.
425 for (int k = 0; k < 3; k++)
426 if (isnan(value[k]))
427 for (int radius = 1; radius <= nn_defined_radius; radius++) {
428 double nearest_radius_squared = (radius + 1) * (radius + 1);
429 for (int ii = -radius; ii <= radius; ii++)
430 for (int jj = -radius; jj <= radius; jj++) {
431 if (!im->in_bounds(point(i + ii, j + jj)))
432 continue;
433 if (ii * ii + jj * jj < nearest_radius_squared
434 && finite(im->get_pixel(i + ii, j + jj)[k])) {
435 value[k] = im->get_pixel(i + ii, j + jj)[k];
436 nearest_radius_squared = ii * ii + jj * jj;
439 if (nearest_radius_squared < (radius + 1) * (radius + 1))
440 break;
444 * Unlinearize
447 pixel unlinearized(exp->unlinearize((value - minval_pixel)
448 / (maxval - minval)));
450 unlinearized = unlinearized.clamp();
452 p->red = (Quantum) round(unlinearized[0] * MaxRGB);
453 p->green = (Quantum) round(unlinearized[1] * MaxRGB);
454 p->blue = (Quantum) round(unlinearized[2] * MaxRGB);
455 p++;
458 if (!SyncImagePixels(mi))
459 break;
462 if (!WriteImage(image_info, mi)) {
465 * Perhaps file type was unknown? Set to PNM by default.
468 strncpy(mi->magick, "PNM", MaxTextExtent);
469 strncpy(image_info->magick, "PNM", MaxTextExtent);
471 if (!WriteImage(image_info, mi)) {
472 fprintf(stderr, "\n\n");
473 CatchException(&mi->exception);
474 fprintf(stderr, "\n");
475 exit(1);
479 DestroyImage(mi);
480 DestroyImageInfo(image_info);
481 #else
482 write_ppm(filename, im, exp, mcv, ppm_type == 2, rezero, exposure_scale || exp_scale_override,
483 nn_defined_radius);
484 #endif
487 static void output(const image *i) {
488 assert (file_count > 0);
489 write_image(output_name(), i, output_exposure);
492 static void vise_write(const char *p, const char *s, const image *i) {
493 static int count = 0;
494 int length = strlen(p) + strlen(s) + 8;
495 char *output_string = (char *) malloc(length * sizeof(char));
497 snprintf(output_string, length, "%s%08d%s", p, count, s);
499 write_image(output_string, i, output_exposure);
501 count++;
504 static exposure &exp(int n) {
505 return *input_exposure[n];
508 static const exposure &const_exp(int n) {
509 return *input_exposure[n];
512 static exposure &exp() {
513 return *output_exposure;
516 static void exp_scale() {
517 exposure_scale = 1;
520 static void exp_noscale() {
521 exposure_scale = 0;
524 static const exposure &const_exp() {
525 return *output_exposure;
528 static const unsigned int bayer(unsigned int n) {
529 if (bayer_specific[n] == IMAGE_BAYER_DEFAULT)
530 return bayer_default;
531 else
532 return bayer_specific[n];
535 static const image *open(unsigned int n) {
536 assert (n < file_count);
537 assert (!files_open[n]);
539 if (latest_close_num >= 0 && n == (unsigned int) latest_close_num) {
540 images[n] = latest_close;
541 latest_close_num = -1;
542 files_open[n] = 1;
543 } else {
545 image *i = read_image(filenames[n], input_exposure[n], "file", bayer(n), (n == 0));
547 images[n] = i;
548 files_open[n] = 1;
550 return images[n];
553 static void open_all() {
554 for (unsigned int n = 0; n < file_count; n++)
555 open(n);
558 static const image *get_open(unsigned int n) {
559 assert (files_open[n]);
560 return images[n];
563 static image *copy(unsigned int n, char *name) {
564 assert (n < file_count);
566 if (files_open[n])
567 return images[n]->clone(name);
568 else {
569 image *i = read_image(filenames[n], input_exposure[n], name, bayer(n), (n == 0));
570 return i;
574 static void close(unsigned int image) {
575 assert (image < file_count);
576 assert (files_open[image]);
578 if (latest_close_num >= 0)
579 delete latest_close;
580 latest_close = images[image];
581 latest_close_num = image;
583 files_open[image] = 0;
586 static void close_all() {
587 for (unsigned int n = 0; n < file_count; n++)
588 close(n);
593 #endif