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 ale_image
*images
;
91 static int *files_open
;
94 * The most recently closed image number.
96 static int latest_close_num
;
101 static double cache_size
;
104 * Number of cached files.
106 static unsigned int cache_count
;
109 * Private methods to init and shut down the file reader.
113 * Initialize the image file handler
115 static void init_image() {
117 InitializeMagick("ale");
122 * Destroy the image file handler
124 static void destroy_image() {
130 static ale_image
read_image_im(const char *filename
, exposure
*exp
, const char *name
,
131 unsigned int bayer
, int init_reference_gain
) {
132 static int warned
= 0;
135 if (MaxRGB
< 65535 && mcv
== 65535 && !warned
) {
136 fprintf(stderr
, "\n\n*** Warning: " MagickPackageName
" has not been compiled with 16 bit support.\n");
137 fprintf(stderr
, "*** Reading input using 8 bits per channel.\n");
138 fprintf(stderr
, "*** \n");
139 fprintf(stderr
, "*** (To silence this warning, specify option --8bpc)\n\n\n");
145 * Patterned after http://www.imagemagick.org/www/api.html
146 * and http://www.imagemagick.org/www/smile.c
149 ExceptionInfo exception
;
151 ImageInfo
*image_info
;
153 FILE *converted_f
= tmpfile();
154 const PixelPacket
*p
;
158 ale_real black_level
= exp
->get_black_level();
160 GetExceptionInfo(&exception
);
161 image_info
= CloneImageInfo((ImageInfo
*) NULL
);
163 strncpy(image_info
->filename
, filename
, MaxTextExtent
);
164 mi
= ReadImage(image_info
, &exception
);
165 if (exception
.severity
!= UndefinedException
) {
166 fprintf(stderr
, "\n\n");
167 CatchException(&exception
);
168 fprintf(stderr
, "\n");
170 if (mi
== (Image
*) NULL
)
173 im
= ale_new_image(accel::context(),
174 (bayer
== IMAGE_BAYER_NONE
) ? ALE_IMAGE_RGB
: ALE_IMAGE_Y
,
175 (image_info
->depth
== 8) ? ALE_TYPE_UINT_8
:
176 ((image_info
->depth
== 16) ? ALE_TYPE_UINT_16
:
177 ((image_info
->depth
== 32) ? ALE_TYPE_UINT_32
: ALE_TYPE_UINT_64
)));
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 long ival
[3] = { p
->red
, p
->green
, p
->blue
};
191 for (int k
= 0; k
< 3; k
++) {
193 if (!ale_has_channel(i
, j
, k
, bayer
))
196 fprintf(converted_f
, "%c", ((char *) ival
)[0]);
197 if (image_info
->depth
>= 16)
198 fprintf(converted_f
, "%c", ((char *) ival
)[1]);
199 if (image_info
->depth
>= 32)
200 fprintf(converted_f
, "%c%c", ((char *) ival
)[2], ((char *) ival
)[3]);
201 if (image_info
->depth
>= 64)
202 fprintf(converted_f
, "%c%c%c%c", ((char *) ival
)[4], ((char *) ival
)[5], ((char *) ival
)[6], ((char *) ival
)[7]); // XXX: ival might be too short for this
210 ale_image_set_file_static(im
, mi
->columns
, mi
->rows
, converted_f
, 0, ppm_void_file_close
, converted_f
);
213 DestroyImageInfo(image_info
);
224 * Read an image from a file
226 static ale_image
read_image(const char *filename
, exposure
*exp
, const char *name
= "file",
227 unsigned int bayer
= IMAGE_BAYER_DEFAULT
, int init_reference_gain
= 0) {
230 if (bayer
== IMAGE_BAYER_DEFAULT
)
231 bayer
= bayer_default
;
233 if (is_eppm(filename
)) {
234 result
= read_ppm(filename
, exp
, bayer
, init_reference_gain
);
238 result
= read_image_im(filename
, exp
, name
, bayer
, init_reference_gain
);
240 result
= read_ppm(filename
, exp
, bayer
);
249 * Handle FILE_COUNT input files with names in array FILENAMES and
250 * output file OUTPUT_FILENAME. FILENAMES should be an array of char *
251 * that is never freed. OUTPUT_FILENAME should be a char * that is
254 * INPUT_EXPOSURE should be an array of FILE_COUNT exposure objects
255 * that is never freed. OUTPUT_EXPOSURE should be an exposure * that
258 static void init(unsigned int _file_count
, const char **_filenames
,
259 const char *_output_filename
, exposure
**_input_exposure
,
260 exposure
*_output_exposure
){
261 assert (_file_count
> 0);
265 filenames
= _filenames
;
266 file_count
= _file_count
;
267 output_filename
= _output_filename
;
268 input_exposure
= _input_exposure
;
269 output_exposure
= _output_exposure
;
271 images
= (ale_image
*)malloc(file_count
* sizeof(ale_image
));
272 bayer_specific
= (unsigned int *)malloc(file_count
* sizeof(unsigned int));
273 files_open
= (int *)calloc(file_count
, sizeof(int));
276 assert (bayer_specific
);
279 if (!images
|| !files_open
|| !bayer_specific
) {
280 fprintf(stderr
, "Unable to allocate memory for images.\n");
284 for (unsigned int i
= 0; i
< file_count
; i
++)
285 bayer_specific
[i
] = IMAGE_BAYER_DEFAULT
;
287 ui::get()->identify_output(output_filename
);
290 static void ppm_plain() {
294 static void ppm_raw() {
298 static void ppm_auto() {
302 fprintf(stderr
, "\n\n*** Error: --auto flag not supported on this build. ***\n"
303 "*** (Hint: Rebuild with IMAGEMAGICK=1) ***\n\n");
308 static void set_default_bayer(unsigned int b
) {
312 static void set_specific_bayer(unsigned int index
, unsigned int b
) {
313 assert (bayer_specific
);
314 bayer_specific
[index
] = b
;
317 static void depth16() {
322 static void depth8() {
327 static void destroy() {
328 assert (file_count
> 0);
332 static unsigned int count() {
333 assert (file_count
> 0);
337 static const char *name(unsigned int image
) {
338 assert (image
< file_count
);
340 return filenames
[image
];
343 static void def_nn(double _nn
) {
344 nn_defined_radius
= _nn
;
347 static const char *output_name() {
348 assert (file_count
> 0);
349 return output_filename
;
353 * Write an image to a file
355 static void write_image(const char *filename
, ale_image im
, int rezero
= 0, int exp_scale_override
= 0, double gamma
= 0.45) {
356 static int warned
= 0;
359 * Handle ALE-specific magical filenames.
362 if (!strcmp(filename
, "dump:")) {
363 FILE *image_data
= ale_image_retain_file(im
);
365 int format
= ale_image_get_format(im
);
366 int type
= ale_image_get_type(im
);
368 fprintf(stderr
, "Image dump: ");
369 for (unsigned int i
= 0; i
< ale_image_get_height(im
); i
++)
370 for (unsigned int j
= 0; j
< ale_image_get_width(im
); j
++) {
371 fprintf(stderr
, "(%d, %d): ", i
, j
);
373 fprintf(stderr
, "[");
375 for (unsigned int k
= 0; k
< ale_image_get_depth(im
); k
++) {
377 unsigned char data
[8];
380 fprintf(stderr
, " ");
384 fscanf(image_data
, "%c", &data
[0]);
385 fprintf(stderr
, "%u", (unsigned int) data
[0]);
388 fscanf(image_data
, "%c%c", &data
[0], &data
[1]);
389 fprintf(stderr
, "%u", (unsigned int) *((unsigned short *) data
));
392 fscanf(image_data
, "%c%c%c%c", &data
[0], &data
[1], &data
[2], &data
[3]);
393 fprintf(stderr
, "%u", *((unsigned int *) data
));
396 fscanf(image_data
, "%c%c%c%c%c%c%c%c", &data
[0], &data
[1], &data
[2], &data
[3], &data
[4], &data
[5], &data
[6], &data
[7]);
397 fprintf(stderr
, "%lu", *((unsigned long *) data
)); // XXX: may not be long enough.
400 fscanf(image_data
, "%c%c%c%c", &data
[0], &data
[1], &data
[2], &data
[3]);
401 fprintf(stderr
, "%f", (double) *((float *) data
));
404 fscanf(image_data
, "%c%c%c%c%c%c%c%c", &data
[0], &data
[1], &data
[2], &data
[3], &data
[4], &data
[5], &data
[6], &data
[7]);
405 fprintf(stderr
, "%f", *((double *) data
));
409 fprintf(stderr
, "] ");
411 fprintf(stderr
, "\n");
413 ale_image_release_file(im
, image_data
);
420 * If necessary, adjust mcv to match library limits.
423 if (MaxRGB
< 65535 && mcv
== 65535) {
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");
434 * Automatic exposure adjustment (don't blow out highlights)
437 ale_real minval
= (rezero
? (ale_real
) ale_image_minval(im
) : (ale_real
) 0);
440 pixel
minval_pixel(minval
, minval
, minval
);
443 if (exposure_scale
|| exp_scale_override
) {
444 ale_real new_maxval
= ale_image_maxval(im
);
446 if (new_maxval
> maxval
)
451 * Nearest-neighbor fill.
454 ale_image temp_image
= ale_image_nn_fill(im
, nn_defined_radius
);
460 ale_image_map_1(temp_image
, temp_image
, "\
461 SET_PIXEL(p, pow((GET_PIXEL(0, p) - (PIXEL(1, 1, 1) * %0f)) / (%1f - %0f), %2f))",
462 minval
, maxval
, gamma
);
467 * Patterned after http://www.imagemagick.org/www/api.html
468 * and http://www.imagemagick.org/www/smile.c
471 ExceptionInfo exception
;
473 ImageInfo
*image_info
;
478 GetExceptionInfo(&exception
);
479 image_info
= CloneImageInfo((ImageInfo
*) NULL
);
480 strncpy(image_info
->filename
, filename
, MaxTextExtent
);
482 mi
= AllocateImage(image_info
);
483 if (mi
== (Image
*) NULL
)
484 MagickError(ResourceLimitError
,
485 "Unable to display image", "MemoryAllocationFailed");
487 mi
->columns
= ale_image_get_width(im
);
488 mi
->rows
= ale_image_get_height(im
);
491 * Set the output image depth
500 * Set compression type
504 mi
->compression
= NoCompression
;
505 image_info
->compression
= NoCompression
;
506 strncpy(mi
->magick
, "PNM", MaxTextExtent
);
507 strncpy(image_info
->magick
, "PNM", MaxTextExtent
);
508 } else if (ppm_type
== 1) {
509 strncpy(mi
->magick
, "PNM", MaxTextExtent
);
510 strncpy(image_info
->magick
, "PNM", MaxTextExtent
);
517 FILE *image_data
= ale_image_retain_file(temp_image
);
519 for (i
= 0; i
< mi
->rows
; i
++) {
520 p
= SetImagePixels(mi
, 0, i
, mi
->columns
, 1);
524 for (j
= 0; j
< mi
->columns
; j
++) {
526 pixel value
= im
->get_pixel(i
, j
);
528 #warning migrate to libale
531 * Get nearest-neighbor defined values.
533 * XXX: While this implementation is correct, it is inefficient
534 * for large radii. A better implementation would search
535 * perimeters of squares of ever-increasing radius, tracking
536 * the best-so-far data until the square perimeter exceeded the
537 * best-so-far radius.
540 for (int k
= 0; k
< 3; k
++)
542 for (int radius
= 1; radius
<= nn_defined_radius
; radius
++) {
543 double nearest_radius_squared
= (radius
+ 1) * (radius
+ 1);
544 for (int ii
= -radius
; ii
<= radius
; ii
++)
545 for (int jj
= -radius
; jj
<= radius
; jj
++) {
546 if (!im
->in_bounds(point(i
+ ii
, j
+ jj
)))
548 if (ii
* ii
+ jj
* jj
< nearest_radius_squared
549 && finite(im
->get_pixel(i
+ ii
, j
+ jj
)[k
])) {
550 value
[k
] = im
->get_pixel(i
+ ii
, j
+ jj
)[k
];
551 nearest_radius_squared
= ii
* ii
+ jj
* jj
;
554 if (nearest_radius_squared
< (radius
+ 1) * (radius
+ 1))
562 pixel
unlinearized(exp
->unlinearize((value
- minval_pixel
)
563 / (maxval
- minval
)));
565 unlinearized
= unlinearized
.clamp();
568 p
->red
= (Quantum
) ale_real_to_int(unlinearized
[0], MaxRGB
);
569 p
->green
= (Quantum
) ale_real_to_int(unlinearized
[1], MaxRGB
);
570 p
->blue
= (Quantum
) ale_real_to_int(unlinearized
[2], MaxRGB
);
574 if (!SyncImagePixels(mi
))
578 ale_image_release_file(temp_image
, image_data
);
580 if (!WriteImage(image_info
, mi
)) {
583 * Perhaps file type was unknown? Set to PNM by default.
586 strncpy(mi
->magick
, "PNM", MaxTextExtent
);
587 strncpy(image_info
->magick
, "PNM", MaxTextExtent
);
589 if (!WriteImage(image_info
, mi
)) {
590 fprintf(stderr
, "\n\n");
591 CatchException(&mi
->exception
);
592 fprintf(stderr
, "\n");
598 DestroyImageInfo(image_info
);
600 write_ppm(filename
, temp_image
, mcv
, ppm_type
== 2);
603 ale_image_release(temp_image
);
608 static void output(const image
*i
) {
609 assert (file_count
> 0);
610 write_image(output_name(), i
, output_exposure
);
613 static void vise_write(const char *p
, const char *s
, const image
*i
) {
614 static int count
= 0;
615 int length
= strlen(p
) + strlen(s
) + 8;
616 char *output_string
= (char *) malloc(length
* sizeof(char));
618 snprintf(output_string
, length
, "%s%08d%s", p
, count
, s
);
620 write_image(output_string
, i
, output_exposure
);
625 static exposure
&exp(int n
) {
626 return *input_exposure
[n
];
629 static const exposure
&const_exp(int n
) {
630 return *input_exposure
[n
];
633 static exposure
&exp() {
634 return *output_exposure
;
637 static void exp_scale() {
641 static void exp_noscale() {
645 static const exposure
&const_exp() {
646 return *output_exposure
;
649 static const unsigned int bayer(unsigned int n
) {
650 if (bayer_specific
[n
] == IMAGE_BAYER_DEFAULT
)
651 return bayer_default
;
653 return bayer_specific
[n
];
656 static const ale_image
open_simple(unsigned int n
) {
657 assert (n
< file_count
);
659 return read_image(filenames
[n
], input_exposure
[n
], "file", bayer(n
), (n
== 0));
662 static const ale_image
open(unsigned int n
) {
663 assert (n
< file_count
);
664 assert (!files_open
[n
]);
668 if (latest_close_num
>= 0 && n
== (unsigned int) latest_close_num
) {
669 latest_close_num
= -1;
676 ui::get()->loading_file();
677 ale_image i
= read_image(filenames
[n
], input_exposure
[n
], "file", bayer(n
), (n
== 0));
684 static void open_all() {
685 for (unsigned int n
= 0; n
< file_count
; n
++)
689 static ale_image
get_open(unsigned int n
) {
690 assert (files_open
[n
]);
696 * XXX: as far as I can tell, 'copy' is currently always used
697 * as a kind of 'retain', so that calls to this can probably be
698 * replaced by calls to an appropriate retain method.
701 static ale_image
copy(unsigned int n
, const char *name
) {
702 assert (n
< file_count
);
705 return images
[n
]->clone(name
);
707 image
*i
= read_image(filenames
[n
], input_exposure
[n
], name
, bayer(n
), (n
== 0));
715 * This method should be replaced by ale_sequence_release_image.
718 static void close(unsigned int image
) {
719 assert (image
< file_count
);
720 assert (files_open
[image
]);
722 files_open
[image
] = 0;
724 if (image
< cache_count
)
727 if (image
== cache_count
) {
728 double image_size
= ((double) images
[image
]->storage_size()) / pow(2, 20);
730 if (image_size
+ cache_size
< cache_size_max
) {
731 cache_size
+= image_size
;
733 ui::get()->cache(cache_size
, cache_size_max
);
736 ui::get()->cache_status(0);
740 if (latest_close_num
>= 0)
741 delete images
[latest_close_num
];
743 latest_close_num
= image
;
746 static void close_all() {
747 for (unsigned int n
= 0; n
< file_count
; n
++)