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
) {
138 static int warned
= 0;
141 if (MaxRGB
< 65535 && mcv
== 65535 && !warned
) {
142 fprintf(stderr
, "\n\n*** Warning: " MagickPackageName
" has not been compiled with 16 bit support.\n");
143 fprintf(stderr
, "*** Reading input using 8 bits per channel.\n");
144 fprintf(stderr
, "*** \n");
145 fprintf(stderr
, "*** (To silence this warning, specify option --8bpc)\n\n\n");
151 * Patterned after http://www.imagemagick.org/www/api.html
152 * and http://www.imagemagick.org/www/smile.c
155 ExceptionInfo exception
;
157 ImageInfo
*image_info
;
159 const PixelPacket
*p
;
163 ale_real black_level
= exp
->get_black_level();
165 GetExceptionInfo(&exception
);
166 image_info
= CloneImageInfo((ImageInfo
*) NULL
);
168 strncpy(image_info
->filename
, filename
, MaxTextExtent
);
169 mi
= ReadImage(image_info
, &exception
);
170 if (exception
.severity
!= UndefinedException
) {
171 fprintf(stderr
, "\n\n");
172 CatchException(&exception
);
173 fprintf(stderr
, "\n");
175 if (mi
== (Image
*) NULL
)
178 if (bayer
== IMAGE_BAYER_NONE
)
179 im
= new_image_ale_real(mi
->rows
, mi
->columns
, 3, name
, exp
);
181 im
= new_image_bayer_ale_real(mi
->rows
, mi
->columns
, 3, bayer
, name
, exp
);
183 for (i
= 0; i
< mi
->rows
; i
++) {
184 p
= AcquireImagePixels(mi
, 0, i
, mi
->columns
, 1, &exception
);
186 if (exception
.severity
!= UndefinedException
)
187 CatchException(&exception
);
191 for (j
= 0; j
< mi
->columns
; j
++) {
193 pixel
input ( ale_real_from_int(p
->red
, MaxRGB
),
194 ale_real_from_int(p
->green
, MaxRGB
),
195 ale_real_from_int(p
->blue
, MaxRGB
) );
197 pixel linear_input
= (exp
->linearize(input
) - exp
->get_multiplier() * black_level
)
200 im
->set_pixel(i
, j
, linear_input
);
207 DestroyImageInfo(image_info
);
218 * Read an image from a file
220 static image
*read_image(const char *filename
, exposure
*exp
, const char *name
= "file",
221 unsigned int bayer
= IMAGE_BAYER_DEFAULT
, int init_reference_gain
= 0) {
224 if (bayer
== IMAGE_BAYER_DEFAULT
)
225 bayer
= bayer_default
;
227 if (is_eppm(filename
)) {
228 result
= read_ppm(filename
, exp
, bayer
, init_reference_gain
);
232 result
= read_image_im_unaccel(filename
, exp
, name
, bayer
, init_reference_gain
);
234 result
= read_ppm(filename
, exp
, bayer
);
238 result
->accel_domain_sequence();
240 image
*accel_result
= new image_accel(result
);
244 result
= accel_result
;
253 * Handle FILE_COUNT input files with names in array FILENAMES and
254 * output file OUTPUT_FILENAME. FILENAMES should be an array of char *
255 * that is never freed. OUTPUT_FILENAME should be a char * that is
258 * INPUT_EXPOSURE should be an array of FILE_COUNT exposure objects
259 * that is never freed. OUTPUT_EXPOSURE should be an exposure * that
262 static void init(unsigned int _file_count
, const char **_filenames
,
263 const char *_output_filename
, exposure
**_input_exposure
,
264 exposure
*_output_exposure
){
265 assert (_file_count
> 0);
269 filenames
= _filenames
;
270 file_count
= _file_count
;
271 output_filename
= _output_filename
;
272 input_exposure
= _input_exposure
;
273 output_exposure
= _output_exposure
;
275 images
= (const image
**)malloc(file_count
* sizeof(image
*));
276 bayer_specific
= (unsigned int *)malloc(file_count
* sizeof(unsigned int));
277 files_open
= (int *)calloc(file_count
, sizeof(int));
280 assert (bayer_specific
);
283 if (!images
|| !files_open
|| !bayer_specific
) {
284 fprintf(stderr
, "Unable to allocate memory for images.\n");
288 for (unsigned int i
= 0; i
< file_count
; i
++)
289 bayer_specific
[i
] = IMAGE_BAYER_DEFAULT
;
291 ui::get()->identify_output(output_filename
);
294 static void ppm_plain() {
298 static void ppm_raw() {
302 static void ppm_auto() {
306 fprintf(stderr
, "\n\n*** Error: --auto flag not supported on this build. ***\n"
307 "*** (Hint: Rebuild with IMAGEMAGICK=1) ***\n\n");
312 static void set_default_bayer(unsigned int b
) {
316 static void set_specific_bayer(unsigned int index
, unsigned int b
) {
317 assert (bayer_specific
);
318 bayer_specific
[index
] = b
;
321 static void depth16() {
326 static void depth8() {
331 static void set_cache(double size
) {
332 cache_size_max
= size
;
335 static void destroy() {
336 assert (file_count
> 0);
340 static unsigned int count() {
341 assert (file_count
> 0);
345 static const char *name(unsigned int image
) {
346 assert (image
< file_count
);
348 return filenames
[image
];
351 static void def_nn(double _nn
) {
352 nn_defined_radius
= _nn
;
355 static const char *output_name() {
356 assert (file_count
> 0);
357 return output_filename
;
361 * Write an image to a file
363 static void write_image(const char *filename
, const image
*im
, exposure
*exp
= output_exposure
, int rezero
= 0, int exp_scale_override
= 0) {
364 static int warned
= 0;
367 * Handle ALE-specific magical filenames.
370 if (!strcmp(filename
, "dump:")) {
371 fprintf(stderr
, "Image dump: ");
372 for (unsigned int i
= 0; i
< im
->height(); i
++)
373 for (unsigned int j
= 0; j
< im
->width(); j
++) {
374 pixel p
= im
->get_pixel(i
, j
);
375 fprintf(stderr
, "(%d, %d): [%f %f %f] ", i
, j
, (double) p
[0], (double) p
[1], (double) p
[2]);
377 fprintf(stderr
, "\n");
382 image
*unaccel_im
= im
->unaccel_equiv();
391 * Patterned after http://www.imagemagick.org/www/api.html
392 * and http://www.imagemagick.org/www/smile.c
395 ExceptionInfo exception
;
397 ImageInfo
*image_info
;
402 GetExceptionInfo(&exception
);
403 image_info
= CloneImageInfo((ImageInfo
*) NULL
);
404 strncpy(image_info
->filename
, filename
, MaxTextExtent
);
406 mi
= AllocateImage(image_info
);
407 if (mi
== (Image
*) NULL
)
408 MagickError(ResourceLimitError
,
409 "Unable to display image", "MemoryAllocationFailed");
411 mi
->columns
= im
->width();
412 mi
->rows
= im
->height();
415 * Set the output image depth
418 if (MaxRGB
< 65535 || mcv
< 65535)
423 if (MaxRGB
< 65535 && mcv
== 65535 && !warned
) {
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");
433 * Set compression type
437 mi
->compression
= NoCompression
;
438 image_info
->compression
= NoCompression
;
439 strncpy(mi
->magick
, "PNM", MaxTextExtent
);
440 strncpy(image_info
->magick
, "PNM", MaxTextExtent
);
441 } else if (ppm_type
== 1) {
442 strncpy(mi
->magick
, "PNM", MaxTextExtent
);
443 strncpy(image_info
->magick
, "PNM", MaxTextExtent
);
447 * Automatic exposure adjustment (don't blow out highlights)
450 ale_real minval
= (rezero
? im
->minval() : (ale_real
) 0);
453 pixel
minval_pixel(minval
, minval
, minval
);
456 if (exposure_scale
|| exp_scale_override
) {
457 ale_real new_maxval
= im
->maxval();
459 if (new_maxval
> maxval
)
467 for (i
= 0; i
< mi
->rows
; i
++) {
468 p
= SetImagePixels(mi
, 0, i
, mi
->columns
, 1);
472 for (j
= 0; j
< mi
->columns
; j
++) {
474 pixel value
= im
->get_pixel(i
, j
);
477 * Get nearest-neighbor defined values.
479 * XXX: While this implementation is correct, it is inefficient
480 * for large radii. A better implementation would search
481 * perimeters of squares of ever-increasing radius, tracking
482 * the best-so-far data until the square perimeter exceeded the
483 * best-so-far radius.
486 for (int k
= 0; k
< 3; k
++)
488 for (int radius
= 1; radius
<= nn_defined_radius
; radius
++) {
489 double nearest_radius_squared
= (radius
+ 1) * (radius
+ 1);
490 for (int ii
= -radius
; ii
<= radius
; ii
++)
491 for (int jj
= -radius
; jj
<= radius
; jj
++) {
492 if (!im
->in_bounds(point(i
+ ii
, j
+ jj
)))
494 if (ii
* ii
+ jj
* jj
< nearest_radius_squared
495 && finite(im
->get_pixel(i
+ ii
, j
+ jj
)[k
])) {
496 value
[k
] = im
->get_pixel(i
+ ii
, j
+ jj
)[k
];
497 nearest_radius_squared
= ii
* ii
+ jj
* jj
;
500 if (nearest_radius_squared
< (radius
+ 1) * (radius
+ 1))
508 pixel
unlinearized(exp
->unlinearize((value
- minval_pixel
)
509 / (maxval
- minval
)));
511 unlinearized
= unlinearized
.clamp();
513 p
->red
= (Quantum
) ale_real_to_int(unlinearized
[0], MaxRGB
);
514 p
->green
= (Quantum
) ale_real_to_int(unlinearized
[1], MaxRGB
);
515 p
->blue
= (Quantum
) ale_real_to_int(unlinearized
[2], MaxRGB
);
519 if (!SyncImagePixels(mi
))
523 if (!WriteImage(image_info
, mi
)) {
526 * Perhaps file type was unknown? Set to PNM by default.
529 strncpy(mi
->magick
, "PNM", MaxTextExtent
);
530 strncpy(image_info
->magick
, "PNM", MaxTextExtent
);
532 if (!WriteImage(image_info
, mi
)) {
533 fprintf(stderr
, "\n\n");
534 CatchException(&mi
->exception
);
535 fprintf(stderr
, "\n");
541 DestroyImageInfo(image_info
);
543 write_ppm(filename
, im
, exp
, mcv
, ppm_type
== 2, rezero
, exposure_scale
|| exp_scale_override
,
552 static void output(const image
*i
) {
553 assert (file_count
> 0);
554 write_image(output_name(), i
, output_exposure
);
557 static void vise_write(const char *p
, const char *s
, const image
*i
) {
558 static int count
= 0;
559 int length
= strlen(p
) + strlen(s
) + 8;
560 char *output_string
= (char *) malloc(length
* sizeof(char));
562 snprintf(output_string
, length
, "%s%08d%s", p
, count
, s
);
564 write_image(output_string
, i
, output_exposure
);
569 static exposure
&exp(int n
) {
570 return *input_exposure
[n
];
573 static const exposure
&const_exp(int n
) {
574 return *input_exposure
[n
];
577 static exposure
&exp() {
578 return *output_exposure
;
581 static void exp_scale() {
585 static void exp_noscale() {
589 static const exposure
&const_exp() {
590 return *output_exposure
;
593 static const unsigned int bayer(unsigned int n
) {
594 if (bayer_specific
[n
] == IMAGE_BAYER_DEFAULT
)
595 return bayer_default
;
597 return bayer_specific
[n
];
600 static const image
*open(unsigned int n
) {
601 assert (n
< file_count
);
602 assert (!files_open
[n
]);
606 if (latest_close_num
>= 0 && n
== (unsigned int) latest_close_num
) {
607 latest_close_num
= -1;
614 ui::get()->loading_file();
615 image
*i
= read_image(filenames
[n
], input_exposure
[n
], "file", bayer(n
), (n
== 0));
622 static void open_all() {
623 for (unsigned int n
= 0; n
< file_count
; n
++)
627 static const image
*get_open(unsigned int n
) {
628 assert (files_open
[n
]);
632 static image
*copy(unsigned int n
, const char *name
) {
633 assert (n
< file_count
);
636 return images
[n
]->clone(name
);
638 image
*i
= read_image(filenames
[n
], input_exposure
[n
], name
, bayer(n
), (n
== 0));
643 static void close(unsigned int image
) {
644 assert (image
< file_count
);
645 assert (files_open
[image
]);
647 files_open
[image
] = 0;
649 if (image
< cache_count
)
652 if (image
== cache_count
) {
653 double image_size
= ((double) images
[image
]->storage_size()) / pow(2, 20);
655 if (image_size
+ cache_size
< cache_size_max
) {
656 cache_size
+= image_size
;
658 ui::get()->cache(cache_size
, cache_size_max
);
661 ui::get()->cache_status(0);
665 if (latest_close_num
>= 0)
666 delete images
[latest_close_num
];
668 latest_close_num
= image
;
671 static void close_all() {
672 for (unsigned int n
= 0; n
< file_count
; n
++)