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__
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 * Maximum cache size, in megabytes (2^20 * bytes), for images not most
101 static double cache_size_max
;
106 static double cache_size
;
109 * Number of cached files.
111 static unsigned int cache_count
;
114 * Private methods to init and shut down the file reader.
118 * Initialize the image file handler
120 static void init_image() {
122 InitializeMagick("ale");
127 * Destroy the image file handler
129 static void destroy_image() {
138 * Methods to read and write image files
142 * Read an image from a file
144 static image
*read_image(const char *filename
, exposure
*exp
, const char *name
= "file",
145 unsigned int bayer
= IMAGE_BAYER_DEFAULT
, int init_reference_gain
= 0) {
146 if (bayer
== IMAGE_BAYER_DEFAULT
)
147 bayer
= bayer_default
;
149 if (is_eppm(filename
)) {
150 return read_ppm(filename
, exp
, bayer
, init_reference_gain
);
155 * Patterned after http://www.imagemagick.org/www/api.html
156 * and http://www.imagemagick.org/www/smile.c
159 ExceptionInfo exception
;
161 ImageInfo
*image_info
;
163 const PixelPacket
*p
;
167 ale_real black_level
= exp
->get_black_level();
169 GetExceptionInfo(&exception
);
170 image_info
= CloneImageInfo((ImageInfo
*) NULL
);
172 strncpy(image_info
->filename
, filename
, MaxTextExtent
);
173 mi
= ReadImage(image_info
, &exception
);
174 if (exception
.severity
!= UndefinedException
) {
175 fprintf(stderr
, "\n\n");
176 CatchException(&exception
);
177 fprintf(stderr
, "\n");
179 if (mi
== (Image
*) NULL
)
182 if (bayer
== IMAGE_BAYER_NONE
)
183 im
= new_image_ale_real(mi
->rows
, mi
->columns
, 3, name
, exp
);
185 im
= new_image_bayer_ale_real(mi
->rows
, mi
->columns
, 3, bayer
, name
, exp
);
187 for (i
= 0; i
< mi
->rows
; i
++) {
188 p
= AcquireImagePixels(mi
, 0, i
, mi
->columns
, 1, &exception
);
190 if (exception
.severity
!= UndefinedException
)
191 CatchException(&exception
);
195 for (j
= 0; j
< mi
->columns
; j
++) {
197 pixel
input ( ale_real_from_int(p
->red
, MaxRGB
),
198 ale_real_from_int(p
->green
, MaxRGB
),
199 ale_real_from_int(p
->blue
, MaxRGB
) );
201 pixel linear_input
= (exp
->linearize(input
) - exp
->get_multiplier() * black_level
)
204 im
->set_pixel(i
, j
, linear_input
);
211 DestroyImageInfo(image_info
);
215 return read_ppm(filename
, exp
, bayer
);
222 * Handle FILE_COUNT input files with names in array FILENAMES and
223 * output file OUTPUT_FILENAME. FILENAMES should be an array of char *
224 * that is never freed. OUTPUT_FILENAME should be a char * that is
227 * INPUT_EXPOSURE should be an array of FILE_COUNT exposure objects
228 * that is never freed. OUTPUT_EXPOSURE should be an exposure * that
231 static void init(unsigned int _file_count
, const char **_filenames
,
232 const char *_output_filename
, exposure
**_input_exposure
,
233 exposure
*_output_exposure
){
234 assert (_file_count
> 0);
238 filenames
= _filenames
;
239 file_count
= _file_count
;
240 output_filename
= _output_filename
;
241 input_exposure
= _input_exposure
;
242 output_exposure
= _output_exposure
;
244 images
= (const image
**)malloc(file_count
* sizeof(image
*));
245 bayer_specific
= (unsigned int *)malloc(file_count
* sizeof(unsigned int));
246 files_open
= (int *)calloc(file_count
, sizeof(int));
249 assert (bayer_specific
);
252 if (!images
|| !files_open
|| !bayer_specific
) {
253 fprintf(stderr
, "Unable to allocate memory for images.\n");
257 for (unsigned int i
= 0; i
< file_count
; i
++)
258 bayer_specific
[i
] = IMAGE_BAYER_DEFAULT
;
260 ui::get()->identify_output(output_filename
);
263 static void ppm_plain() {
267 static void ppm_raw() {
271 static void ppm_auto() {
275 fprintf(stderr
, "\n\n*** Error: --auto flag not supported on this build. ***\n"
276 "*** (Hint: Rebuild with IMAGEMAGICK=1) ***\n\n");
281 static void set_default_bayer(unsigned int b
) {
285 static void set_specific_bayer(unsigned int index
, unsigned int b
) {
286 assert (bayer_specific
);
287 bayer_specific
[index
] = b
;
290 static void depth16() {
295 static void depth8() {
300 static void set_cache(double size
) {
301 cache_size_max
= size
;
304 static void destroy() {
305 assert (file_count
> 0);
309 static unsigned int count() {
310 assert (file_count
> 0);
314 static const char *name(unsigned int image
) {
315 assert (image
< file_count
);
317 return filenames
[image
];
320 static void def_nn(double _nn
) {
321 nn_defined_radius
= _nn
;
324 static const char *output_name() {
325 assert (file_count
> 0);
326 return output_filename
;
330 * Write an image to a file
332 static void write_image(const char *filename
, const image
*im
, exposure
*exp
= output_exposure
, int rezero
= 0, int exp_scale_override
= 0) {
334 * Handle ALE-specific magical filenames.
337 if (!strcmp(filename
, "dump:")) {
338 fprintf(stderr
, "Image dump: ");
339 for (unsigned int i
= 0; i
< im
->height(); i
++)
340 for (unsigned int j
= 0; j
< im
->width(); j
++) {
341 pixel p
= im
->get_pixel(i
, j
);
342 fprintf(stderr
, "(%d, %d): [%f %f %f] ", i
, j
, (double) p
[0], (double) p
[1], (double) p
[2]);
344 fprintf(stderr
, "\n");
352 * Patterned after http://www.imagemagick.org/www/api.html
353 * and http://www.imagemagick.org/www/smile.c
356 ExceptionInfo exception
;
358 ImageInfo
*image_info
;
363 GetExceptionInfo(&exception
);
364 image_info
= CloneImageInfo((ImageInfo
*) NULL
);
365 strncpy(image_info
->filename
, filename
, MaxTextExtent
);
367 mi
= AllocateImage(image_info
);
368 if (mi
== (Image
*) NULL
)
369 MagickError(ResourceLimitError
,
370 "Unable to display image", "MemoryAllocationFailed");
372 mi
->columns
= im
->width();
373 mi
->rows
= im
->height();
376 * Set the output image depth
379 if (MaxRGB
< 65535 || mcv
< 65535)
384 if (MaxRGB
< 65535 && mcv
== 65535) {
385 fprintf(stderr
, "\n\n*** Warning: 16 bit-per-channel file output was specified,\n");
386 fprintf(stderr
, "*** but ImageMagick has not been compiled with support for this.\n");
387 fprintf(stderr
, "*** Writing output using 8 bits per channel.\n");
391 * Set compression type
395 mi
->compression
= NoCompression
;
396 image_info
->compression
= NoCompression
;
397 strncpy(mi
->magick
, "PNM", MaxTextExtent
);
398 strncpy(image_info
->magick
, "PNM", MaxTextExtent
);
399 } else if (ppm_type
== 1) {
400 strncpy(mi
->magick
, "PNM", MaxTextExtent
);
401 strncpy(image_info
->magick
, "PNM", MaxTextExtent
);
405 * Automatic exposure adjustment (don't blow out highlights)
408 ale_real minval
= (rezero
? im
->minval() : (ale_real
) 0);
411 pixel
minval_pixel(minval
, minval
, minval
);
414 if (exposure_scale
|| exp_scale_override
) {
415 ale_real new_maxval
= im
->maxval();
417 if (new_maxval
> maxval
)
425 for (i
= 0; i
< mi
->rows
; i
++) {
426 p
= SetImagePixels(mi
, 0, i
, mi
->columns
, 1);
430 for (j
= 0; j
< mi
->columns
; j
++) {
432 pixel value
= im
->get_pixel(i
, j
);
435 * Get nearest-neighbor defined values.
437 * XXX: While this implementation is correct, it is inefficient
438 * for large radii. A better implementation would search
439 * perimeters of squares of ever-increasing radius, tracking
440 * the best-so-far data until the square perimeter exceeded the
441 * best-so-far radius.
444 for (int k
= 0; k
< 3; k
++)
446 for (int radius
= 1; radius
<= nn_defined_radius
; radius
++) {
447 double nearest_radius_squared
= (radius
+ 1) * (radius
+ 1);
448 for (int ii
= -radius
; ii
<= radius
; ii
++)
449 for (int jj
= -radius
; jj
<= radius
; jj
++) {
450 if (!im
->in_bounds(point(i
+ ii
, j
+ jj
)))
452 if (ii
* ii
+ jj
* jj
< nearest_radius_squared
453 && finite(im
->get_pixel(i
+ ii
, j
+ jj
)[k
])) {
454 value
[k
] = im
->get_pixel(i
+ ii
, j
+ jj
)[k
];
455 nearest_radius_squared
= ii
* ii
+ jj
* jj
;
458 if (nearest_radius_squared
< (radius
+ 1) * (radius
+ 1))
466 pixel
unlinearized(exp
->unlinearize((value
- minval_pixel
)
467 / (maxval
- minval
)));
469 unlinearized
= unlinearized
.clamp();
471 p
->red
= (Quantum
) ale_real_to_int(unlinearized
[0], MaxRGB
);
472 p
->green
= (Quantum
) ale_real_to_int(unlinearized
[1], MaxRGB
);
473 p
->blue
= (Quantum
) ale_real_to_int(unlinearized
[2], MaxRGB
);
477 if (!SyncImagePixels(mi
))
481 if (!WriteImage(image_info
, mi
)) {
484 * Perhaps file type was unknown? Set to PNM by default.
487 strncpy(mi
->magick
, "PNM", MaxTextExtent
);
488 strncpy(image_info
->magick
, "PNM", MaxTextExtent
);
490 if (!WriteImage(image_info
, mi
)) {
491 fprintf(stderr
, "\n\n");
492 CatchException(&mi
->exception
);
493 fprintf(stderr
, "\n");
499 DestroyImageInfo(image_info
);
501 write_ppm(filename
, im
, exp
, mcv
, ppm_type
== 2, rezero
, exposure_scale
|| exp_scale_override
,
506 static void output(const image
*i
) {
507 assert (file_count
> 0);
508 write_image(output_name(), i
, output_exposure
);
511 static void vise_write(const char *p
, const char *s
, const image
*i
) {
512 static int count
= 0;
513 int length
= strlen(p
) + strlen(s
) + 8;
514 char *output_string
= (char *) malloc(length
* sizeof(char));
516 snprintf(output_string
, length
, "%s%08d%s", p
, count
, s
);
518 write_image(output_string
, i
, output_exposure
);
523 static exposure
&exp(int n
) {
524 return *input_exposure
[n
];
527 static const exposure
&const_exp(int n
) {
528 return *input_exposure
[n
];
531 static exposure
&exp() {
532 return *output_exposure
;
535 static void exp_scale() {
539 static void exp_noscale() {
543 static const exposure
&const_exp() {
544 return *output_exposure
;
547 static const unsigned int bayer(unsigned int n
) {
548 if (bayer_specific
[n
] == IMAGE_BAYER_DEFAULT
)
549 return bayer_default
;
551 return bayer_specific
[n
];
554 static const image
*open(unsigned int n
) {
555 assert (n
< file_count
);
556 assert (!files_open
[n
]);
560 if (latest_close_num
>= 0 && n
== (unsigned int) latest_close_num
) {
561 latest_close_num
= -1;
568 ui::get()->loading_file();
569 image
*i
= read_image(filenames
[n
], input_exposure
[n
], "file", bayer(n
), (n
== 0));
576 static void open_all() {
577 for (unsigned int n
= 0; n
< file_count
; n
++)
581 static const image
*get_open(unsigned int n
) {
582 assert (files_open
[n
]);
586 static image
*copy(unsigned int n
, const char *name
) {
587 assert (n
< file_count
);
590 return images
[n
]->clone(name
);
592 image
*i
= read_image(filenames
[n
], input_exposure
[n
], name
, bayer(n
), (n
== 0));
597 static void close(unsigned int image
) {
598 assert (image
< file_count
);
599 assert (files_open
[image
]);
601 files_open
[image
] = 0;
603 if (image
< cache_count
)
606 if (image
== cache_count
) {
607 double image_size
= ((double) images
[image
]->storage_size()) / pow(2, 20);
609 if (image_size
+ cache_size
< cache_size_max
) {
610 cache_size
+= image_size
;
612 ui::get()->cache(cache_size
, cache_size_max
);
615 ui::get()->cache_status(0);
619 if (latest_close_num
>= 0)
620 delete images
[latest_close_num
];
622 latest_close_num
= image
;
625 static void close_all() {
626 for (unsigned int n
= 0; n
< file_count
; n
++)