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__
30 #include "image_ale_real.h"
31 #include "image_bayer_ale_real.h"
33 #include "exposure/exposure.h"
34 #include "exposure/exposure_default.h"
39 * Private data members
45 * 0 = No type selected
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() {
111 InitializeMagick("ale");
116 * Destroy the image file handler
118 static void destroy_image() {
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
);
144 * Patterned after http://www.imagemagick.org/www/api.html
145 * and http://www.imagemagick.org/www/smile.c
148 ExceptionInfo exception
;
150 ImageInfo
*image_info
;
152 const PixelPacket
*p
;
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
)
169 if (bayer
== IMAGE_BAYER_NONE
)
170 im
= new image_ale_real(mi
->rows
, mi
->columns
, 3, name
, exp
);
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
);
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
));
194 DestroyImageInfo(image_info
);
198 return read_ppm(filename
, exp
, bayer
);
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
210 * INPUT_EXPOSURE should be an array of FILE_COUNT exposure objects
211 * that is never freed. OUTPUT_EXPOSURE should be an exposure * that
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);
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));
232 assert (bayer_specific
);
235 if (!images
|| !files_open
|| !bayer_specific
) {
236 fprintf(stderr
, "Unable to allocate memory for images.\n");
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",
248 static void ppm_plain() {
252 static void ppm_raw() {
256 static void ppm_auto() {
260 fprintf(stderr
, "\n\n*** Error: --auto flag not supported on this build. ***\n"
261 "*** (Hint: Rebuild with IMAGEMAGICK=1) ***\n\n");
266 static void set_default_bayer(unsigned int 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() {
280 static void depth8() {
285 static void destroy() {
286 assert (file_count
> 0);
290 static unsigned int count() {
291 assert (file_count
> 0);
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");
333 * Patterned after http://www.imagemagick.org/www/api.html
334 * and http://www.imagemagick.org/www/smile.c
337 ExceptionInfo exception
;
339 ImageInfo
*image_info
;
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)
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
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)
389 ale_real minval
= (rezero
? im
->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
)
406 for (i
= 0; i
< mi
->rows
; i
++) {
407 p
= SetImagePixels(mi
, 0, i
, mi
->columns
, 1);
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
++)
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
)))
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))
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
);
458 if (!SyncImagePixels(mi
))
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");
480 DestroyImageInfo(image_info
);
482 write_ppm(filename
, im
, exp
, mcv
, ppm_type
== 2, rezero
, exposure_scale
|| exp_scale_override
,
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
);
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() {
520 static void exp_noscale() {
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
;
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;
545 image
*i
= read_image(filenames
[n
], input_exposure
[n
], "file", bayer(n
), (n
== 0));
553 static void open_all() {
554 for (unsigned int n
= 0; n
< file_count
; n
++)
558 static const image
*get_open(unsigned int n
) {
559 assert (files_open
[n
]);
563 static image
*copy(unsigned int n
, char *name
) {
564 assert (n
< file_count
);
567 return images
[n
]->clone(name
);
569 image
*i
= read_image(filenames
[n
], input_exposure
[n
], name
, bayer(n
), (n
== 0));
574 static void close(unsigned int image
) {
575 assert (image
< file_count
);
576 assert (files_open
[image
]);
578 if (latest_close_num
>= 0)
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
++)