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"
32 #include "image_accel.h"
34 #include "exposure/exposure.h"
35 #include "exposure/exposure_default.h"
40 * Private data members
46 * 0 = No type selected
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 const image
**images
;
91 static int *files_open
;
94 * The most recently closed image number.
96 static int latest_close_num
;
99 * Maximum cache size, in megabytes (2^20 * bytes), for images not most
102 static double cache_size_max
;
107 static double cache_size
;
110 * Number of cached files.
112 static unsigned int cache_count
;
115 * Private methods to init and shut down the file reader.
119 * Initialize the image file handler
121 static void init_image() {
123 InitializeMagick("ale");
128 * Destroy the image file handler
130 static void destroy_image() {
136 static image
*read_image_im_unaccel(const char *filename
, exposure
*exp
, const char *name
,
137 unsigned int bayer
, int init_reference_gain
) {
140 if (MaxRGB
< 65535 && mcv
== 65535) {
141 fprintf(stderr
, "\n\n*** Warning: 16 bit-per-channel file output was specified,\n");
142 fprintf(stderr
, "*** but ImageMagick has not been compiled with support for 16 bits.\n");
143 fprintf(stderr
, "*** Reading input using 8 bits per channel.\n\n\n");
147 * Patterned after http://www.imagemagick.org/www/api.html
148 * and http://www.imagemagick.org/www/smile.c
151 ExceptionInfo exception
;
153 ImageInfo
*image_info
;
155 const PixelPacket
*p
;
159 ale_real black_level
= exp
->get_black_level();
161 GetExceptionInfo(&exception
);
162 image_info
= CloneImageInfo((ImageInfo
*) NULL
);
164 strncpy(image_info
->filename
, filename
, MaxTextExtent
);
165 mi
= ReadImage(image_info
, &exception
);
166 if (exception
.severity
!= UndefinedException
) {
167 fprintf(stderr
, "\n\n");
168 CatchException(&exception
);
169 fprintf(stderr
, "\n");
171 if (mi
== (Image
*) NULL
)
174 if (bayer
== IMAGE_BAYER_NONE
)
175 im
= new_image_ale_real(mi
->rows
, mi
->columns
, 3, name
, exp
);
177 im
= new_image_bayer_ale_real(mi
->rows
, mi
->columns
, 3, bayer
, name
, exp
);
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
);
187 for (j
= 0; j
< mi
->columns
; j
++) {
189 pixel
input ( ale_real_from_int(p
->red
, MaxRGB
),
190 ale_real_from_int(p
->green
, MaxRGB
),
191 ale_real_from_int(p
->blue
, MaxRGB
) );
193 pixel linear_input
= (exp
->linearize(input
) - exp
->get_multiplier() * black_level
)
196 im
->set_pixel(i
, j
, linear_input
);
203 DestroyImageInfo(image_info
);
214 * Read an image from a file
216 static image
*read_image(const char *filename
, exposure
*exp
, const char *name
= "file",
217 unsigned int bayer
= IMAGE_BAYER_DEFAULT
, int init_reference_gain
= 0) {
220 if (bayer
== IMAGE_BAYER_DEFAULT
)
221 bayer
= bayer_default
;
223 if (is_eppm(filename
)) {
224 result
= read_ppm(filename
, exp
, bayer
, init_reference_gain
);
228 result
= read_image_im_unaccel(filename
, exp
, name
, bayer
, init_reference_gain
);
230 result
= read_ppm(filename
, exp
, bayer
);
233 result
->accel_domain_sequence();
235 image
*accel_result
= new image_accel(result
);
239 result
= accel_result
;
247 * Handle FILE_COUNT input files with names in array FILENAMES and
248 * output file OUTPUT_FILENAME. FILENAMES should be an array of char *
249 * that is never freed. OUTPUT_FILENAME should be a char * that is
252 * INPUT_EXPOSURE should be an array of FILE_COUNT exposure objects
253 * that is never freed. OUTPUT_EXPOSURE should be an exposure * that
256 static void init(unsigned int _file_count
, const char **_filenames
,
257 const char *_output_filename
, exposure
**_input_exposure
,
258 exposure
*_output_exposure
){
259 assert (_file_count
> 0);
263 filenames
= _filenames
;
264 file_count
= _file_count
;
265 output_filename
= _output_filename
;
266 input_exposure
= _input_exposure
;
267 output_exposure
= _output_exposure
;
269 images
= (const image
**)malloc(file_count
* sizeof(image
*));
270 bayer_specific
= (unsigned int *)malloc(file_count
* sizeof(unsigned int));
271 files_open
= (int *)calloc(file_count
, sizeof(int));
274 assert (bayer_specific
);
277 if (!images
|| !files_open
|| !bayer_specific
) {
278 fprintf(stderr
, "Unable to allocate memory for images.\n");
282 for (unsigned int i
= 0; i
< file_count
; i
++)
283 bayer_specific
[i
] = IMAGE_BAYER_DEFAULT
;
285 ui::get()->identify_output(output_filename
);
288 static void ppm_plain() {
292 static void ppm_raw() {
296 static void ppm_auto() {
300 fprintf(stderr
, "\n\n*** Error: --auto flag not supported on this build. ***\n"
301 "*** (Hint: Rebuild with IMAGEMAGICK=1) ***\n\n");
306 static void set_default_bayer(unsigned int b
) {
310 static void set_specific_bayer(unsigned int index
, unsigned int b
) {
311 assert (bayer_specific
);
312 bayer_specific
[index
] = b
;
315 static void depth16() {
320 static void depth8() {
325 static void set_cache(double size
) {
326 cache_size_max
= size
;
329 static void destroy() {
330 assert (file_count
> 0);
334 static unsigned int count() {
335 assert (file_count
> 0);
339 static const char *name(unsigned int image
) {
340 assert (image
< file_count
);
342 return filenames
[image
];
345 static void def_nn(double _nn
) {
346 nn_defined_radius
= _nn
;
349 static const char *output_name() {
350 assert (file_count
> 0);
351 return output_filename
;
355 * Write an image to a file
357 static void write_image(const char *filename
, const image
*im
, exposure
*exp
= output_exposure
, int rezero
= 0, int exp_scale_override
= 0) {
359 * Handle ALE-specific magical filenames.
362 if (!strcmp(filename
, "dump:")) {
363 fprintf(stderr
, "Image dump: ");
364 for (unsigned int i
= 0; i
< im
->height(); i
++)
365 for (unsigned int j
= 0; j
< im
->width(); j
++) {
366 pixel p
= im
->get_pixel(i
, j
);
367 fprintf(stderr
, "(%d, %d): [%f %f %f] ", i
, j
, (double) p
[0], (double) p
[1], (double) p
[2]);
369 fprintf(stderr
, "\n");
374 image
*unaccel_im
= im
->unaccel_equiv();
383 * Patterned after http://www.imagemagick.org/www/api.html
384 * and http://www.imagemagick.org/www/smile.c
387 ExceptionInfo exception
;
389 ImageInfo
*image_info
;
394 GetExceptionInfo(&exception
);
395 image_info
= CloneImageInfo((ImageInfo
*) NULL
);
396 strncpy(image_info
->filename
, filename
, MaxTextExtent
);
398 mi
= AllocateImage(image_info
);
399 if (mi
== (Image
*) NULL
)
400 MagickError(ResourceLimitError
,
401 "Unable to display image", "MemoryAllocationFailed");
403 mi
->columns
= im
->width();
404 mi
->rows
= im
->height();
407 * Set the output image depth
410 if (MaxRGB
< 65535 || mcv
< 65535)
415 if (MaxRGB
< 65535 && mcv
== 65535) {
416 fprintf(stderr
, "\n\n*** Warning: 16 bit-per-channel file output was specified,\n");
417 fprintf(stderr
, "*** but ImageMagick has not been compiled with support for this.\n");
418 fprintf(stderr
, "*** Writing output using 8 bits per channel.\n\n\n");
422 * Set compression type
426 mi
->compression
= NoCompression
;
427 image_info
->compression
= NoCompression
;
428 strncpy(mi
->magick
, "PNM", MaxTextExtent
);
429 strncpy(image_info
->magick
, "PNM", MaxTextExtent
);
430 } else if (ppm_type
== 1) {
431 strncpy(mi
->magick
, "PNM", MaxTextExtent
);
432 strncpy(image_info
->magick
, "PNM", MaxTextExtent
);
436 * Automatic exposure adjustment (don't blow out highlights)
439 ale_real minval
= (rezero
? im
->minval() : (ale_real
) 0);
442 pixel
minval_pixel(minval
, minval
, minval
);
445 if (exposure_scale
|| exp_scale_override
) {
446 ale_real new_maxval
= im
->maxval();
448 if (new_maxval
> maxval
)
456 for (i
= 0; i
< mi
->rows
; i
++) {
457 p
= SetImagePixels(mi
, 0, i
, mi
->columns
, 1);
461 for (j
= 0; j
< mi
->columns
; j
++) {
463 pixel value
= im
->get_pixel(i
, j
);
466 * Get nearest-neighbor defined values.
468 * XXX: While this implementation is correct, it is inefficient
469 * for large radii. A better implementation would search
470 * perimeters of squares of ever-increasing radius, tracking
471 * the best-so-far data until the square perimeter exceeded the
472 * best-so-far radius.
475 for (int k
= 0; k
< 3; k
++)
477 for (int radius
= 1; radius
<= nn_defined_radius
; radius
++) {
478 double nearest_radius_squared
= (radius
+ 1) * (radius
+ 1);
479 for (int ii
= -radius
; ii
<= radius
; ii
++)
480 for (int jj
= -radius
; jj
<= radius
; jj
++) {
481 if (!im
->in_bounds(point(i
+ ii
, j
+ jj
)))
483 if (ii
* ii
+ jj
* jj
< nearest_radius_squared
484 && finite(im
->get_pixel(i
+ ii
, j
+ jj
)[k
])) {
485 value
[k
] = im
->get_pixel(i
+ ii
, j
+ jj
)[k
];
486 nearest_radius_squared
= ii
* ii
+ jj
* jj
;
489 if (nearest_radius_squared
< (radius
+ 1) * (radius
+ 1))
497 pixel
unlinearized(exp
->unlinearize((value
- minval_pixel
)
498 / (maxval
- minval
)));
500 unlinearized
= unlinearized
.clamp();
502 p
->red
= (Quantum
) ale_real_to_int(unlinearized
[0], MaxRGB
);
503 p
->green
= (Quantum
) ale_real_to_int(unlinearized
[1], MaxRGB
);
504 p
->blue
= (Quantum
) ale_real_to_int(unlinearized
[2], MaxRGB
);
508 if (!SyncImagePixels(mi
))
512 if (!WriteImage(image_info
, mi
)) {
515 * Perhaps file type was unknown? Set to PNM by default.
518 strncpy(mi
->magick
, "PNM", MaxTextExtent
);
519 strncpy(image_info
->magick
, "PNM", MaxTextExtent
);
521 if (!WriteImage(image_info
, mi
)) {
522 fprintf(stderr
, "\n\n");
523 CatchException(&mi
->exception
);
524 fprintf(stderr
, "\n");
530 DestroyImageInfo(image_info
);
532 write_ppm(filename
, im
, exp
, mcv
, ppm_type
== 2, rezero
, exposure_scale
|| exp_scale_override
,
541 static void output(const image
*i
) {
542 assert (file_count
> 0);
543 write_image(output_name(), i
, output_exposure
);
546 static void vise_write(const char *p
, const char *s
, const image
*i
) {
547 static int count
= 0;
548 int length
= strlen(p
) + strlen(s
) + 8;
549 char *output_string
= (char *) malloc(length
* sizeof(char));
551 snprintf(output_string
, length
, "%s%08d%s", p
, count
, s
);
553 write_image(output_string
, i
, output_exposure
);
558 static exposure
&exp(int n
) {
559 return *input_exposure
[n
];
562 static const exposure
&const_exp(int n
) {
563 return *input_exposure
[n
];
566 static exposure
&exp() {
567 return *output_exposure
;
570 static void exp_scale() {
574 static void exp_noscale() {
578 static const exposure
&const_exp() {
579 return *output_exposure
;
582 static const unsigned int bayer(unsigned int n
) {
583 if (bayer_specific
[n
] == IMAGE_BAYER_DEFAULT
)
584 return bayer_default
;
586 return bayer_specific
[n
];
589 static const image
*open(unsigned int n
) {
590 assert (n
< file_count
);
591 assert (!files_open
[n
]);
595 if (latest_close_num
>= 0 && n
== (unsigned int) latest_close_num
) {
596 latest_close_num
= -1;
603 ui::get()->loading_file();
604 image
*i
= read_image(filenames
[n
], input_exposure
[n
], "file", bayer(n
), (n
== 0));
611 static void open_all() {
612 for (unsigned int n
= 0; n
< file_count
; n
++)
616 static const image
*get_open(unsigned int n
) {
617 assert (files_open
[n
]);
621 static image
*copy(unsigned int n
, const char *name
) {
622 assert (n
< file_count
);
625 return images
[n
]->clone(name
);
627 image
*i
= read_image(filenames
[n
], input_exposure
[n
], name
, bayer(n
), (n
== 0));
632 static void close(unsigned int image
) {
633 assert (image
< file_count
);
634 assert (files_open
[image
]);
636 files_open
[image
] = 0;
638 if (image
< cache_count
)
641 if (image
== cache_count
) {
642 double image_size
= ((double) images
[image
]->storage_size()) / pow(2, 20);
644 if (image_size
+ cache_size
< cache_size_max
) {
645 cache_size
+= image_size
;
647 ui::get()->cache(cache_size
, cache_size_max
);
650 ui::get()->cache_status(0);
654 if (latest_close_num
>= 0)
655 delete images
[latest_close_num
];
657 latest_close_num
= image
;
660 static void close_all() {
661 for (unsigned int n
= 0; n
< file_count
; n
++)