d2/image_rw: rewrite magical 'dump:' write target for varying endianness.
[Ale.git] / d2 / image_rw.h
blob74882c8cdfb0fb8e169033dc9a19e2a5b589e390
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__
29 #include "image.h"
30 #include "image_ale_real.h"
31 #include "image_bayer_ale_real.h"
32 #include "image_accel.h"
33 #include "ppm.h"
34 #include "exposure/exposure.h"
35 #include "exposure/exposure_default.h"
37 class image_rw {
40 * Private data members
44 * PPM type
46 * 0 = No type selected
47 * 1 = PPM Raw
48 * 2 = PPM Plain
50 static int ppm_type;
53 * Bit depth
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;
99 * Actual cache size.
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() {
116 #ifdef USE_MAGICK
117 InitializeMagick("ale");
118 #endif
122 * Destroy the image file handler
124 static void destroy_image() {
125 #ifdef USE_MAGICK
126 DestroyMagick();
127 #endif
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;
133 #ifdef USE_MAGICK
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");
141 warned = 1;
145 * Patterned after http://www.imagemagick.org/www/api.html
146 * and http://www.imagemagick.org/www/smile.c
149 ExceptionInfo exception;
150 Image *mi;
151 ImageInfo *image_info;
152 ale_image im;
153 FILE *converted_f = tmpfile();
154 const PixelPacket *p;
156 unsigned int i, j;
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)
171 exit(1);
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);
184 if (p == NULL)
185 exit(1);
187 for (j = 0; j < mi->columns; j++) {
189 Quantum 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))
194 continue;
196 if (image_info->depth <= 8) {
197 cl_uchar c = ival[k];
198 fwrite(&c, sizeof(cl_uchar), 1, converted_f);
199 } else if (image_info->depth <= 16) {
200 cl_ushort c = ival[k];
201 fwrite(&c, sizeof(cl_ushort), 1, converted_f);
202 } else if (image_info->depth <= 32) {
203 cl_uint c = ival[k];
204 fwrite(&c, sizeof(cl_uint), 1, converted_f);
205 } else if (image_info->depth <= 64) {
206 cl_ulong c = ival[k];
207 fwrite(&c, sizeof(cl_ulong), 1, converted_f);
208 } else {
209 fprintf(stderr, "error: unable to handle image depth %u\n", (unsigned int) image_info->depth);
210 exit(1);
214 p++;
218 ale_image_set_file_static(im, mi->columns, mi->rows, converted_f, 0, ppm_void_file_close, converted_f);
220 DestroyImage(mi);
221 DestroyImageInfo(image_info);
223 return im;
224 #else
225 return NULL;
226 #endif
229 public:
232 * Read an image from a file
234 static ale_image read_image(const char *filename, exposure *exp, const char *name = "file",
235 unsigned int bayer = IMAGE_BAYER_DEFAULT, int init_reference_gain = 0) {
236 ale_image result;
238 if (bayer == IMAGE_BAYER_DEFAULT)
239 bayer = bayer_default;
241 if (is_eppm(filename)) {
242 result = read_ppm(filename, exp, bayer, init_reference_gain);
245 #ifdef USE_MAGICK
246 result = read_image_im(filename, exp, name, bayer, init_reference_gain);
247 #else
248 result = read_ppm(filename, exp, bayer);
249 #endif
251 return result;
255 * Initializer.
257 * Handle FILE_COUNT input files with names in array FILENAMES and
258 * output file OUTPUT_FILENAME. FILENAMES should be an array of char *
259 * that is never freed. OUTPUT_FILENAME should be a char * that is
260 * never freed.
262 * INPUT_EXPOSURE should be an array of FILE_COUNT exposure objects
263 * that is never freed. OUTPUT_EXPOSURE should be an exposure * that
264 * is never freed.
266 static void init(unsigned int _file_count, const char **_filenames,
267 const char *_output_filename, exposure **_input_exposure,
268 exposure *_output_exposure){
269 assert (_file_count > 0);
271 init_image();
273 filenames = _filenames;
274 file_count = _file_count;
275 output_filename = _output_filename;
276 input_exposure = _input_exposure;
277 output_exposure = _output_exposure;
279 images = (ale_image *)malloc(file_count * sizeof(ale_image));
280 bayer_specific = (unsigned int *)malloc(file_count * sizeof(unsigned int));
281 files_open = (int *)calloc(file_count, sizeof(int));
283 assert (images);
284 assert (bayer_specific);
285 assert (files_open);
287 if (!images || !files_open || !bayer_specific) {
288 fprintf(stderr, "Unable to allocate memory for images.\n");
289 exit(1);
292 for (unsigned int i = 0; i < file_count; i++)
293 bayer_specific[i] = IMAGE_BAYER_DEFAULT;
295 ui::get()->identify_output(output_filename);
298 static void ppm_plain() {
299 ppm_type = 2;
302 static void ppm_raw() {
303 ppm_type = 1;
306 static void ppm_auto() {
307 #ifdef USE_MAGICK
308 ppm_type = 0;
309 #else
310 fprintf(stderr, "\n\n*** Error: --auto flag not supported on this build. ***\n"
311 "*** (Hint: Rebuild with IMAGEMAGICK=1) ***\n\n");
312 exit(1);
313 #endif
316 static void set_default_bayer(unsigned int b) {
317 bayer_default = b;
320 static void set_specific_bayer(unsigned int index, unsigned int b) {
321 assert (bayer_specific);
322 bayer_specific[index] = b;
325 static void depth16() {
326 num_bits = 16;
327 mcv = 65535;
330 static void depth8() {
331 num_bits = 8;
332 mcv = 255;
335 static void destroy() {
336 assert (file_count > 0);
337 destroy_image();
340 static unsigned int count() {
341 assert (file_count > 0);
342 return file_count;
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, ale_image im, int rezero = 0, int exp_scale_override = 0, double gamma = 0.45) {
364 static int warned = 0;
367 * Handle ALE-specific magical filenames.
370 if (!strcmp(filename, "dump:")) {
371 FILE *image_data = ale_image_retain_file(im);
373 int format = ale_image_get_format(im);
374 int type = ale_image_get_type(im);
376 fprintf(stderr, "Image dump: ");
377 for (unsigned int i = 0; i < ale_image_get_height(im); i++)
378 for (unsigned int j = 0; j < ale_image_get_width(im); j++) {
379 fprintf(stderr, "(%d, %d): ", i, j);
381 fprintf(stderr, "[");
383 for (unsigned int k = 0; k < ale_image_get_depth(im); k++) {
385 if (k != 0)
386 fprintf(stderr, " ");
388 switch (type) {
389 ALE_TYPE_UINT_8: {
390 cl_uchar data;
391 assert(fread(&data, sizeof(cl_uchar), 1, image_data));
392 fprintf(stderr, "%u", (unsigned int) data);
393 break; }
394 ALE_TYPE_UINT_16: {
395 cl_ushort data;
396 assert(fread(&data, sizeof(cl_ushort), 1, image_data));
397 fprintf(stderr, "%u", (unsigned int) data);
398 break; }
399 ALE_TYPE_UINT_32: {
400 cl_uint data;
401 assert(fread(&data, sizeof(cl_uint), 1, image_data));
402 fprintf(stderr, "%u", (unsigned int) data);
403 break; }
404 ALE_TYPE_UINT_64: {
405 cl_ulong data;
406 assert(fread(&data, sizeof(cl_ulong), 1, image_data));
407 fprintf(stderr, "%llu", data);
408 break; }
409 ALE_TYPE_FLOAT_32: {
410 cl_float data;
411 assert(fread(&data, sizeof(cl_float), 1, image_data));
412 fprintf(stderr, "%f", (double) data);
413 break; }
414 ALE_TYPE_FLOAT_64: {
415 double data;
416 assert(fread(&data, sizeof(double), 1, image_data));
417 fprintf(stderr, "%f", data);
418 break; }
421 fprintf(stderr, "] ");
423 fprintf(stderr, "\n");
425 ale_image_release_file(im, image_data);
427 return;
430 #ifdef USE_MAGICK
432 * If necessary, adjust mcv to match library limits.
435 if (MaxRGB < 65535 && mcv == 65535) {
436 fprintf(stderr, "\n\n*** Warning: " MagickPackageName " has not been compiled with 16 bit support.\n");
437 fprintf(stderr, "*** Writing output using 8 bits per channel.\n");
438 fprintf(stderr, "*** \n");
439 fprintf(stderr, "*** (To silence this warning, specify option --8bpc)\n\n\n");
441 mcv = 255;
445 * We currently can't handle mcv greater than 65535 here.
448 assert(mcv <= 65535);
450 if (mcv > 65535) {
451 fprintf(stderr, "error: I don't know how to produce greater than 16-bit output.\n");
452 exit(1);
454 #endif
457 * Automatic exposure adjustment (don't blow out highlights)
459 ale_real maxval = 1;
460 ale_real minval = (rezero ? (ale_real) ale_image_minval(im) : (ale_real) 0);
461 if (minval > 0)
462 minval = 0;
463 pixel minval_pixel(minval, minval, minval);
466 if (exposure_scale || exp_scale_override) {
467 ale_real new_maxval = ale_image_maxval(im);
469 if (new_maxval > maxval)
470 maxval = new_maxval;
474 * Nearest-neighbor fill.
477 ale_image temp_image = ale_image_nn_fill(im, nn_defined_radius);
480 * Unlinearize and quantize
483 ale_image quantized_image = ale_new_image(accel::context(),
484 ale_image_get_format(temp_image), (mcv > 255) ?
485 ALE_TYPE_UINT_16 : ALE_TYPE_UINT_8);
487 ale_image_map_1(quantized_image, temp_image, "\
488 SET_PIXEL(p, CLAMP(pow((GET_PIXEL(0, p) - (PIXEL(1, 1, 1) * %0f)) / (%1f - %0f), %2f)) * %3f)",
489 minval, maxval, gamma, (double) ((mcv > 255) ? 65535 : 255));
491 ale_image_release(temp_image);
493 #ifdef USE_MAGICK
496 * Patterned after http://www.imagemagick.org/www/api.html
497 * and http://www.imagemagick.org/www/smile.c
500 ExceptionInfo exception;
501 Image *mi;
502 ImageInfo *image_info;
503 PixelPacket *p;
505 unsigned int i, j;
507 GetExceptionInfo(&exception);
508 image_info = CloneImageInfo((ImageInfo *) NULL);
509 strncpy(image_info->filename, filename, MaxTextExtent);
511 mi = AllocateImage(image_info);
512 if (mi == (Image *) NULL)
513 MagickError(ResourceLimitError,
514 "Unable to display image", "MemoryAllocationFailed");
516 mi->columns = ale_image_get_width(im);
517 mi->rows = ale_image_get_height(im);
520 * Set the output image depth
523 if (mcv < 65535)
524 mi->depth = 8;
525 else
526 mi->depth = 16;
529 * Set compression type
532 if (ppm_type == 2) {
533 mi->compression = NoCompression;
534 image_info->compression = NoCompression;
535 strncpy(mi->magick, "PNM", MaxTextExtent);
536 strncpy(image_info->magick, "PNM", MaxTextExtent);
537 } else if (ppm_type == 1) {
538 strncpy(mi->magick, "PNM", MaxTextExtent);
539 strncpy(image_info->magick, "PNM", MaxTextExtent);
543 * Write the image
546 FILE *image_data = ale_image_retain_file(quantized_image);
548 for (i = 0; i < mi->rows; i++) {
549 p = SetImagePixels(mi, 0, i, mi->columns, 1);
550 if (p == NULL)
551 break;
553 for (j = 0; j < mi->columns; j++) {
555 cl_ushort val[3];
557 for (int k = 0; k < 3; k++) {
558 if (mcv <= 255) {
559 val[k] = fgetc(image_data);
560 } else {
561 assert(fread(&(val[k]), sizeof(cl_ushort), 1, image_data));
565 p->red = (Quantum) val[0];
566 p->green = (Quantum) val[1];
567 p->blue = (Quantum) val[2];
568 p++;
571 if (!SyncImagePixels(mi))
572 break;
575 ale_image_release_file(quantized_image, image_data);
577 if (!WriteImage(image_info, mi)) {
580 * Perhaps file type was unknown? Set to PNM by default.
583 strncpy(mi->magick, "PNM", MaxTextExtent);
584 strncpy(image_info->magick, "PNM", MaxTextExtent);
586 if (!WriteImage(image_info, mi)) {
587 fprintf(stderr, "\n\n");
588 CatchException(&mi->exception);
589 fprintf(stderr, "\n");
590 exit(1);
594 DestroyImage(mi);
595 DestroyImageInfo(image_info);
596 #else
597 write_ppm(filename, quantized_image, mcv, ppm_type == 2);
598 #endif
600 ale_image_release(quantized_image);
605 static void output(const image *i) {
606 assert (file_count > 0);
607 write_image(output_name(), i, output_exposure);
610 static void vise_write(const char *p, const char *s, const image *i) {
611 static int count = 0;
612 int length = strlen(p) + strlen(s) + 8;
613 char *output_string = (char *) malloc(length * sizeof(char));
615 snprintf(output_string, length, "%s%08d%s", p, count, s);
617 write_image(output_string, i, output_exposure);
619 count++;
622 static exposure &exp(int n) {
623 return *input_exposure[n];
626 static const exposure &const_exp(int n) {
627 return *input_exposure[n];
630 static exposure &exp() {
631 return *output_exposure;
634 static void exp_scale() {
635 exposure_scale = 1;
638 static void exp_noscale() {
639 exposure_scale = 0;
642 static const exposure &const_exp() {
643 return *output_exposure;
646 static const unsigned int bayer(unsigned int n) {
647 if (bayer_specific[n] == IMAGE_BAYER_DEFAULT)
648 return bayer_default;
649 else
650 return bayer_specific[n];
653 static const ale_image open_simple(unsigned int n) {
654 assert (n < file_count);
656 return read_image(filenames[n], input_exposure[n], "file", bayer(n), (n == 0));
659 static const ale_image open(unsigned int n) {
660 assert (n < file_count);
661 assert (!files_open[n]);
663 files_open[n] = 1;
665 if (latest_close_num >= 0 && n == (unsigned int) latest_close_num) {
666 latest_close_num = -1;
667 return images[n];
670 if (n < cache_count)
671 return images[n];
673 ui::get()->loading_file();
674 ale_image i = read_image(filenames[n], input_exposure[n], "file", bayer(n), (n == 0));
676 images[n] = i;
678 return images[n];
681 static void open_all() {
682 for (unsigned int n = 0; n < file_count; n++)
683 open(n);
686 static ale_image get_open(unsigned int n) {
687 assert (files_open[n]);
688 return images[n];
691 #if 0
693 * XXX: as far as I can tell, 'copy' is currently always used
694 * as a kind of 'retain', so that calls to this can probably be
695 * replaced by calls to an appropriate retain method.
698 static ale_image copy(unsigned int n, const char *name) {
699 assert (n < file_count);
701 if (files_open[n])
702 return images[n]->clone(name);
703 else {
704 image *i = read_image(filenames[n], input_exposure[n], name, bayer(n), (n == 0));
705 return i;
708 #endif
710 #if 0
712 * This method should be replaced by ale_sequence_release_image.
715 static void close(unsigned int image) {
716 assert (image < file_count);
717 assert (files_open[image]);
719 files_open[image] = 0;
721 if (image < cache_count)
722 return;
724 if (image == cache_count) {
725 double image_size = ((double) images[image]->storage_size()) / pow(2, 20);
727 if (image_size + cache_size < cache_size_max) {
728 cache_size += image_size;
729 cache_count++;
730 ui::get()->cache(cache_size, cache_size_max);
731 return;
732 } else {
733 ui::get()->cache_status(0);
737 if (latest_close_num >= 0)
738 delete images[latest_close_num];
740 latest_close_num = image;
743 static void close_all() {
744 for (unsigned int n = 0; n < file_count; n++)
745 close(n);
747 #endif
751 #endif