Parent Directory
|
Revision Log
0.1 release
1 /* 2 hdrtools GIMP plugin 3 4 Copyright (C) 2007 Shawn Kirst <skirst@fuse.net> 5 6 This program is free software; you can redistribute it and/or 7 modify it under the terms of the GNU General Public 8 License as published by the Free Software Foundation; either 9 version 2 of the License, or (at your option) any later version. 10 11 This program 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 GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; see the file COPYING. If not, write to 18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 Boston, MA 02111-1307, USA. 20 */ 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <ctype.h> 26 #include <float.h> 27 28 #include <gtk/gtk.h> 29 30 #include <libgimp/gimp.h> 31 #include <libgimp/gimpui.h> 32 33 static inline float max(float a, float b) 34 { 35 return(a > b ? a : b); 36 } 37 38 static inline float min(float a, float b) 39 { 40 return(a < b ? a : b); 41 42 } 43 44 static inline float clamp(float x, float l, float h) 45 { 46 return(max(l, min(h, x))); 47 } 48 49 typedef struct rgbe_header_s 50 { 51 int width; 52 int height; 53 int flags; 54 float gamma; 55 float exposure; 56 } rgbe_header_t; 57 58 typedef enum rgbe_flags_e 59 { 60 RGBE_HAS_GAMMA = 1 << 0, 61 RGBE_HAS_EXPOSURE = 1 << 1 62 } rgbe_flags_t; 63 64 #define PROG_NAME "hdrtools" 65 #define LOAD_PROC "file_rgbe_load" 66 #define SAVE_PROC "file_rgbe_save" 67 68 static gint g_run_interactive; 69 static int g_runme = 0; 70 71 static void query(void); 72 static void run(const gchar *name, gint nparams, const GimpParam *param, 73 gint *nreturn_vals, GimpParam **return_vals); 74 static int rgbe_read_header(rgbe_header_t *hdr, FILE *fp); 75 static int rgbe_read_pixels(FILE *fp, unsigned char *data, int num); 76 static int rgbe_read_pixels_RLE(FILE *fp, unsigned char *data, 77 int width, int height); 78 static gint32 read_rgbe_image(gchar *filename); 79 static GimpPDBStatusType write_rgbe_image(gchar *filename, gint32 imageID, 80 gint32 drawableID); 81 static void convert_rgbe_to_rgbdiv8(GimpPreview *preview, 82 GimpDrawable *drawable); 83 static void tonemap_image(GimpPreview *preview, GimpDrawable *drawable); 84 static int tonemap_dialog(GimpDrawable *drawable); 85 static int rgbd8_dialog(GimpDrawable *drawable); 86 static int read_rgbe_dialog(void); 87 static int write_rgbe_dialog(void); 88 89 GimpPlugInInfo PLUG_IN_INFO = 90 { 91 0, 0, query, run 92 }; 93 94 enum 95 { 96 IMAGE_TYPE_RGBE, 97 IMAGE_TYPE_RGBDIV8 98 }; 99 100 /* plug-in data storage structures */ 101 102 static struct 103 { 104 gboolean preview; 105 int imgtype; 106 int tonemap; 107 int usefilelevels; 108 float exposure; 109 float gamma; 110 } g_tonemap_vals = { 1, IMAGE_TYPE_RGBE, 0, 1, 1.0f, 2.2f }; 111 112 static struct 113 { 114 int rle; 115 int writelevels; 116 float exposure; 117 float gamma; 118 } g_write_vals = { 1, 0, 1.0f, 2.2f }; 119 120 static struct 121 { 122 gboolean preview; 123 float range; 124 } g_rgbd8_vals = { 1, 1.0f }; 125 126 MAIN() 127 128 static void query(void) 129 { 130 static GimpParamDef load_args[]= 131 { 132 {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, 133 {GIMP_PDB_STRING, "filename", "The name of the file to load"}, 134 {GIMP_PDB_STRING, "raw_filename", "The name entered"}, 135 {GIMP_PDB_INT32, "tonemap", "Tone map the loaded image"}, 136 {GIMP_PDB_INT32, "use_file_levels", "Use exposure and gamma levels in file for tone mapping"}, 137 {GIMP_PDB_FLOAT, "exposure", "Exposure level (default 1.0)"}, 138 {GIMP_PDB_FLOAT, "gamma", "Gamma level (default 2.2)"} 139 }; 140 141 static GimpParamDef load_return_vals[]= 142 { 143 {GIMP_PDB_IMAGE, "image", "Output image"} 144 }; 145 146 static GimpParamDef save_args[]= 147 { 148 {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, 149 {GIMP_PDB_IMAGE, "image", "Input image"}, 150 {GIMP_PDB_DRAWABLE, "drawable", "Drawable to save"}, 151 {GIMP_PDB_STRING, "filename", "The name of the file to save the image as"}, 152 {GIMP_PDB_STRING, "raw_filename", "The name entered"} 153 }; 154 155 static GimpParamDef rgbd8_args[] = 156 { 157 {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, 158 {GIMP_PDB_IMAGE, "image", "Input image (unused)"}, 159 {GIMP_PDB_DRAWABLE, "drawable", "Input drawable"}, 160 {GIMP_PDB_FLOAT, "range", "Map values [0..1] to [0..range] (default 1.0)"} 161 }; 162 163 static GimpParamDef tonemap_args[] = 164 { 165 {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, 166 {GIMP_PDB_IMAGE, "image", "Input image (unused)"}, 167 {GIMP_PDB_DRAWABLE, "drawable", "Input drawable"}, 168 {GIMP_PDB_FLOAT, "exposure", "Exposure"}, 169 {GIMP_PDB_FLOAT, "gamma", "Gamma"}, 170 }; 171 172 gimp_install_procedure(LOAD_PROC, 173 "Loads files in Radiance RGBE format", 174 "Loads files in Radiance RGBE format", 175 "Shawn Kirst", 176 "Shawn Kirst", 177 "2007", 178 "<Load>/Radiance RGBE", 179 0, 180 GIMP_PLUGIN, 181 G_N_ELEMENTS(load_args), 182 G_N_ELEMENTS(load_return_vals), 183 load_args, load_return_vals); 184 185 gimp_register_magic_load_handler(LOAD_PROC, 186 "hdr", 187 "", 188 "0,string,#?RADIANCE"); 189 190 gimp_install_procedure(SAVE_PROC, 191 "Saves files in Radiance RGBE format", 192 "Saves files in Radiance RGBE format", 193 "Shawn Kirst", 194 "Copyright 2007 Shawn Kirst", 195 "2007", 196 "<Save>/Radiance RGBE", 197 "RGBA", 198 GIMP_PLUGIN, 199 G_N_ELEMENTS(save_args), 0, 200 save_args, 0); 201 202 gimp_register_save_handler(SAVE_PROC, "hdr", ""); 203 204 gimp_install_procedure("convert_rgbe_to_rgbdiv8", 205 "Converts image from Radiance RGBE to RGBdiv8 format", 206 "foo!", 207 "Shawn Kirst", 208 "Copyright 2007 Shawn Kirst", 209 "2007", 210 "<Image>/Filters/Colors/HDR Tools/Convert Radiance RGBE to RGBdiv8...", 211 "RGBA", 212 GIMP_PLUGIN, 213 G_N_ELEMENTS(rgbd8_args), 0, 214 rgbd8_args, NULL); 215 216 gimp_install_procedure("plug_in_tonemap_rgbe", 217 "Converts Radiance RGBE data to LDR RGB", 218 "foo!", 219 "Shawn Kirst", 220 "Copyright 2007 Shawn Kirst", 221 "2007", 222 "<Image>/Filters/Colors/HDR Tools/Tone map Radiance RGBE image", 223 "RGBA", 224 GIMP_PLUGIN, 225 G_N_ELEMENTS(tonemap_args), 0, 226 tonemap_args, NULL); 227 228 gimp_install_procedure("plug_in_tonemap_rgbdiv8", 229 "Converts HDR RGBdiv8 data to LDR RGB", 230 "foo!", 231 "Shawn Kirst", 232 "Copyright 2007 Shawn Kirst", 233 "2007", 234 "<Image>/Filters/Colors/HDR Tools/Tone map RGBdiv8 image", 235 "RGBA", 236 GIMP_PLUGIN, 237 G_N_ELEMENTS(tonemap_args), 0, 238 tonemap_args, NULL); 239 } 240 241 static void run(const gchar *name, gint nparams, const GimpParam *param, 242 gint *nreturn_vals, GimpParam **return_vals) 243 { 244 static GimpParam values[2]; 245 GimpRunMode run_mode; 246 GimpPDBStatusType status = GIMP_PDB_SUCCESS; 247 gint32 imageID, drawableID; 248 GimpDrawable *drawable; 249 GimpExportReturn export = GIMP_EXPORT_CANCEL; 250 251 run_mode = param[0].data.d_int32; 252 253 *nreturn_vals = 1; 254 *return_vals = values; 255 256 values[0].type = GIMP_PDB_STATUS; 257 values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; 258 259 if(!strcmp(name, LOAD_PROC)) 260 { 261 switch(run_mode) 262 { 263 case GIMP_RUN_INTERACTIVE: 264 g_run_interactive = 1; 265 gimp_ui_init(PROG_NAME, 1); 266 267 if(!gimp_get_data(name, &g_tonemap_vals)) 268 { 269 g_tonemap_vals.tonemap = 0; 270 g_tonemap_vals.usefilelevels = 1; 271 g_tonemap_vals.exposure = 1.0f; 272 g_tonemap_vals.gamma = 2.2f; 273 } 274 275 if(!read_rgbe_dialog()) 276 { 277 status = GIMP_PDB_CANCEL; 278 } 279 break; 280 case GIMP_RUN_NONINTERACTIVE: 281 g_run_interactive = 0; 282 if(nparams != 7) 283 status = GIMP_PDB_CALLING_ERROR; 284 else 285 { 286 g_tonemap_vals.tonemap = param[3].data.d_int32; 287 g_tonemap_vals.usefilelevels = param[4].data.d_int32; 288 g_tonemap_vals.exposure = param[5].data.d_float; 289 g_tonemap_vals.gamma = param[6].data.d_float; 290 } 291 break; 292 default: 293 break; 294 } 295 296 if(status == GIMP_PDB_SUCCESS) 297 { 298 imageID = read_rgbe_image(param[1].data.d_string); 299 if(imageID != -1) 300 { 301 *nreturn_vals = 2; 302 values[1].type = GIMP_PDB_IMAGE; 303 values[1].data.d_image = imageID; 304 305 if(g_run_interactive) 306 gimp_set_data(name, &g_tonemap_vals, sizeof(g_tonemap_vals)); 307 } 308 else 309 status = GIMP_PDB_EXECUTION_ERROR; 310 } 311 } 312 else if(!strcmp(name, SAVE_PROC)) 313 { 314 imageID = param[1].data.d_int32; 315 drawableID = param[2].data.d_int32; 316 317 switch(run_mode) 318 { 319 case GIMP_RUN_INTERACTIVE: 320 case GIMP_RUN_WITH_LAST_VALS: 321 gimp_ui_init(PROG_NAME, 0); 322 export = gimp_export_image(&imageID, &drawableID, 323 "Radiance RGBE", 324 (GIMP_EXPORT_CAN_HANDLE_RGB | 325 GIMP_EXPORT_CAN_HANDLE_ALPHA)); 326 if(export == GIMP_EXPORT_CANCEL) 327 { 328 values[0].data.d_status = GIMP_PDB_CANCEL; 329 return; 330 } 331 default: 332 break; 333 } 334 335 switch(run_mode) 336 { 337 case GIMP_RUN_INTERACTIVE: 338 g_run_interactive = 1; 339 if(!gimp_get_data(name, &g_write_vals)) 340 { 341 g_write_vals.rle = 1; 342 g_write_vals.writelevels = 0; 343 g_write_vals.exposure = 1.0f; 344 g_write_vals.gamma = 2.2f; 345 } 346 if(!write_rgbe_dialog()) 347 { 348 values[0].data.d_status = GIMP_PDB_CANCEL; 349 return; 350 } 351 break; 352 case GIMP_RUN_NONINTERACTIVE: 353 g_run_interactive = 0; 354 if(nparams != 5) 355 status = GIMP_PDB_CALLING_ERROR; 356 break; 357 case GIMP_RUN_WITH_LAST_VALS: 358 g_run_interactive = 1; 359 gimp_get_data(name, &g_write_vals); 360 break; 361 default: 362 break; 363 } 364 365 if(status == GIMP_PDB_SUCCESS) 366 { 367 status = write_rgbe_image(param[3].data.d_string, imageID, 368 drawableID); 369 if(g_run_interactive) 370 gimp_set_data(name, &g_write_vals, sizeof(g_write_vals)); 371 } 372 373 if(export == GIMP_EXPORT_EXPORT) 374 gimp_image_delete(imageID); 375 } 376 else if(!strcmp(name, "convert_rgbe_to_rgbdiv8")) 377 { 378 *nreturn_vals = 1; 379 380 drawable = gimp_drawable_get(param[2].data.d_drawable); 381 382 switch(run_mode) 383 { 384 case GIMP_RUN_NONINTERACTIVE: 385 g_run_interactive = 0; 386 if(nparams != 4) 387 status = GIMP_PDB_CALLING_ERROR; 388 g_rgbd8_vals.range = clamp(param[3].data.d_float, 0, 1); 389 break; 390 case GIMP_RUN_WITH_LAST_VALS: 391 g_run_interactive = 1; 392 gimp_get_data(name, &g_rgbd8_vals); 393 break; 394 case GIMP_RUN_INTERACTIVE: 395 g_run_interactive = 1; 396 gimp_ui_init(PROG_NAME, 1); 397 gimp_get_data(name, &g_rgbd8_vals); 398 if(!rgbd8_dialog(drawable)) 399 { 400 status = GIMP_PDB_CANCEL; 401 } 402 break; 403 } 404 405 if(status == GIMP_PDB_SUCCESS) 406 { 407 convert_rgbe_to_rgbdiv8(NULL, drawable); 408 if(g_run_interactive) 409 gimp_set_data(name, &g_rgbd8_vals, sizeof(g_rgbd8_vals)); 410 gimp_displays_flush(); 411 gimp_drawable_detach(drawable); 412 } 413 } 414 else if(!strcmp(name, "plug_in_tonemap_rgbe") || 415 !strcmp(name, "plug_in_tonemap_rgbdiv8")) 416 { 417 int imgtype = !strcmp(name, "plug_in_tonemap_rgbe") ? IMAGE_TYPE_RGBE : IMAGE_TYPE_RGBDIV8; 418 419 *nreturn_vals = 1; 420 421 drawable = gimp_drawable_get(param[2].data.d_drawable); 422 423 switch(run_mode) 424 { 425 case GIMP_RUN_INTERACTIVE: 426 gimp_ui_init(PROG_NAME, 1); 427 428 if(!gimp_get_data(name, &g_tonemap_vals)) 429 { 430 g_tonemap_vals.preview = 1; 431 g_tonemap_vals.exposure = 1.0f; 432 g_tonemap_vals.gamma = 2.2f; 433 } 434 435 g_tonemap_vals.imgtype = imgtype; 436 437 if(!tonemap_dialog(drawable)) 438 { 439 gimp_drawable_detach(drawable); 440 return; 441 } 442 break; 443 case GIMP_RUN_NONINTERACTIVE: 444 if(nparams != 5) 445 status = GIMP_PDB_CALLING_ERROR; 446 else 447 { 448 g_tonemap_vals.exposure = param[3].data.d_float; 449 g_tonemap_vals.gamma = param[4].data.d_float; 450 } 451 break; 452 case GIMP_RUN_WITH_LAST_VALS: 453 gimp_get_data(name, &g_tonemap_vals); 454 g_tonemap_vals.imgtype = imgtype; 455 break; 456 default: 457 break; 458 } 459 460 tonemap_image(NULL, drawable); 461 462 if(run_mode != GIMP_RUN_NONINTERACTIVE) 463 gimp_displays_flush(); 464 465 if(run_mode == GIMP_RUN_INTERACTIVE) 466 gimp_set_data(name, &g_tonemap_vals, sizeof(g_tonemap_vals)); 467 468 gimp_drawable_detach(drawable); 469 } 470 else 471 status = GIMP_PDB_CALLING_ERROR; 472 473 values[0].data.d_status = status; 474 } 475 476 static int rgbe_read_header(rgbe_header_t *hdr, FILE *fp) 477 { 478 char buf[128]; 479 float val; 480 481 hdr->flags = 0; 482 483 if(fgets(buf, sizeof(buf), fp) == 0) 484 return(-1); 485 486 if(strncmp(buf, "#?RADIANCE", 10)) 487 return(-2); 488 489 while(fgets(buf, sizeof(buf), fp)) 490 { 491 if(buf[0] == '#') 492 { 493 // eat comment 494 } 495 else if(strncmp(buf, "FORMAT=", 7) == 0) 496 { 497 // eat format 498 } 499 else if(strncmp(buf, "SOFTWARE=", 9) == 0) 500 { 501 // eat creator 502 } 503 else if(sscanf(buf, "GAMMA=%g", &val) == 1) 504 { 505 hdr->gamma = val; 506 hdr->flags |= RGBE_HAS_GAMMA; 507 } 508 else if(sscanf(buf, "EXPOSURE=%g", &val) == 1) 509 { 510 hdr->exposure = val; 511 hdr->flags |= RGBE_HAS_EXPOSURE; 512 } 513 else 514 break; 515 } 516 517 if(strcmp(buf, "\n") != 0) 518 { 519 printf("\"%s\"\n", buf); 520 return(-3); 521 } 522 523 if(fgets(buf, sizeof(buf), fp) == 0) 524 return(-4); 525 526 if(sscanf(buf, "-Y %d +X %d", &hdr->height, &hdr->width) < 2) 527 return(-5); 528 529 return(0); 530 } 531 532 static int rgbe_read_pixels(FILE *fp, unsigned char *data, int num) 533 { 534 int n = num * 4; 535 int r = fread(data, 1, n, fp); 536 return(-(n != r)); 537 } 538 539 static int rgbe_read_pixels_RLE(FILE *fp, unsigned char *data, 540 int width, int height) 541 { 542 unsigned char rgbe[4], *buffer, *ptr, *end, *dst; 543 int i, count, rc = 0, h = height; 544 unsigned char buf[2]; 545 546 dst = data; 547 548 if((width < 8) || (width > 0x7fff)) 549 return(rgbe_read_pixels(fp, data, width * height)); 550 551 buffer = 0; 552 553 while(h > 0) 554 { 555 if(fread(rgbe, 1, 4, fp) != 4) 556 { 557 rc = -1; 558 goto read_error; 559 } 560 561 if((rgbe[0] != 2) || (rgbe[1] != 2) || (rgbe[2] & 0x80)) 562 { 563 data[0] = rgbe[0]; 564 data[1] = rgbe[1]; 565 data[2] = rgbe[2]; 566 data[3] = rgbe[3]; 567 568 if(buffer) 569 g_free(buffer); 570 571 rc = rgbe_read_pixels(fp, &data[4], (width * h) - 1); 572 573 return(rc ? -2 : 0); 574 } 575 576 if((((int)rgbe[2]) << 8 | rgbe[3]) != width) 577 { 578 rc = -3; 579 goto read_error; 580 } 581 582 if(buffer == 0) 583 buffer = g_malloc(4 * width); 584 585 ptr = buffer; 586 587 for(i = 0; i < 4; ++i) 588 { 589 end = &buffer[(i + 1) * width]; 590 while(ptr < end) 591 { 592 if(fread(buf, 1, 2, fp) != 2) 593 { 594 rc = -4; 595 goto read_error; 596 } 597 598 if(buf[0] > 128) 599 { 600 count = buf[0] - 128; 601 if((count == 0) || (count > (end - ptr))) 602 { 603 rc = -5; 604 goto read_error; 605 } 606 607 while(count-- > 0) 608 *ptr++ = buf[1]; 609 } 610 else 611 { 612 count = buf[0]; 613 if((count == 0) || (count > (end - ptr))) 614 { 615 rc = -6; 616 goto read_error; 617 } 618 619 *ptr++ = buf[1]; 620 621 if(--count > 0) 622 { 623 if(fread(ptr, 1, count, fp) != count) 624 { 625 rc = -7; 626 goto read_error; 627 } 628 629 ptr += count; 630 } 631 } 632 } 633 } 634 635 for(i = 0; i < width; ++i) 636 { 637 dst[4 * i + 0] = buffer[i]; 638 dst[4 * i + 1] = buffer[i + width]; 639 dst[4 * i + 2] = buffer[i + 2 * width]; 640 dst[4 * i + 3] = buffer[i + 3 * width]; 641 } 642 643 dst += 4 * width; 644 645 --h; 646 647 if(g_run_interactive) 648 gimp_progress_update((gdouble)(height - h) / (gdouble)height); 649 } 650 651 read_error: 652 653 if(buffer) 654 g_free(buffer); 655 656 return(rc); 657 } 658 659 static gint32 read_rgbe_image(gchar *filename) 660 { 661 FILE *fp; 662 int rc; 663 rgbe_header_t hdr; 664 unsigned char *pixels; 665 gchar *tmp; 666 GimpPixelRgn pixel_rgn; 667 gint32 image, layer; 668 GimpDrawable *drawable; 669 670 if(g_run_interactive) 671 { 672 tmp = g_strdup_printf("Loading %s:", filename); 673 gimp_progress_init(tmp); 674 g_free(tmp); 675 } 676 677 fp = fopen(filename, "rb"); 678 if(fp == 0) 679 { 680 g_message("%s: can't open \"%s\"", PROG_NAME, filename); 681 return(-1); 682 } 683 684 rc = rgbe_read_header(&hdr, fp); 685 686 if(rc != 0) 687 { 688 g_message("rgbe_read_header() = %d\n", rc); 689 fclose(fp); 690 return(-1); 691 } 692 693 if(g_tonemap_vals.usefilelevels) 694 { 695 if(hdr.flags & RGBE_HAS_EXPOSURE) 696 g_tonemap_vals.exposure = hdr.exposure; 697 else 698 g_tonemap_vals.exposure = 1.0f; 699 700 if(hdr.flags & RGBE_HAS_GAMMA) 701 g_tonemap_vals.gamma = hdr.gamma; 702 else 703 g_tonemap_vals.gamma = 2.2f; 704 } 705 706 pixels = g_malloc(4 * hdr.width * hdr.height); 707 if(pixels == 0) 708 { 709 g_message("Can't allocate pixel buffer\n%s", filename); 710 fclose(fp); 711 return(-1); 712 } 713 714 image = gimp_image_new(hdr.width, hdr.height, GIMP_RGB); 715 if(image == -1) 716 { 717 g_message("Can't allocate new image\n%s", filename); 718 fclose(fp); 719 g_free(pixels); 720 return(-1); 721 } 722 723 layer = gimp_layer_new(image, "Background", hdr.width, hdr.height, 724 GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE); 725 726 gimp_image_set_filename(image, filename); 727 gimp_image_add_layer(image, layer, 0); 728 drawable = gimp_drawable_get(layer); 729 730 rc = rgbe_read_pixels_RLE(fp, pixels, hdr.width, hdr.height); 731 if(rc != 0) 732 { 733 g_message("rgbe_read_pixels_RLE() = %d\n", rc); 734 fclose(fp); 735 g_free(pixels); 736 return(-1); 737 } 738 739 fclose(fp); 740 741 if(g_run_interactive) 742 gimp_progress_update(1.0); 743 744 gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width, 745 drawable->height, 1, 0); 746 gimp_pixel_rgn_set_rect(&pixel_rgn, pixels, 0, 0, drawable->width, 747 drawable->height); 748 749 gimp_drawable_flush(drawable); 750 751 if(g_tonemap_vals.tonemap) 752 { 753 g_tonemap_vals.imgtype = IMAGE_TYPE_RGBE; 754 tonemap_image(NULL, drawable); 755 } 756 757 gimp_drawable_detach(drawable); 758 759 g_free(pixels); 760 761 return(image); 762 } 763 764 static int rgbe_write_pixels(FILE *fp, unsigned char *data, int num) 765 { 766 int n = 4 * num; 767 int w = fwrite(data, 1, n, fp); 768 return(-(w != n)); 769 } 770 771 static int rgbe_write_bytes_RLE(FILE *fp, unsigned char *data, int num) 772 { 773 #define MIN_RUN_LENGTH 4 774 775 int cur, beg_run, run_count, old_run_count, nonrun_count; 776 unsigned char buf[2]; 777 778 cur = 0; 779 while(cur < num) 780 { 781 beg_run = cur; 782 783 run_count = old_run_count = 0; 784 while((run_count < MIN_RUN_LENGTH) && (beg_run < num)) 785 { 786 beg_run += run_count; 787 old_run_count = run_count; 788 run_count = 1; 789 while((beg_run + run_count < num) && (run_count < 127) && 790 (data[beg_run] == data[beg_run + run_count])) 791 run_count++; 792 } 793 794 if((old_run_count > 1) && (old_run_count == beg_run - cur)) 795 { 796 buf[0] = 128 + old_run_count; 797 buf[1] = data[cur]; 798 if(fwrite(buf, 2, 1, fp) < 1) 799 return(-1); 800 cur = beg_run; 801 } 802 803 while(cur < beg_run) 804 { 805 nonrun_count = beg_run - cur; 806 if(nonrun_count > 128) 807 nonrun_count = 128; 808 buf[0] = nonrun_count; 809 if(fwrite(buf, 1, 1, fp) < 1) 810 return(-1); 811 if(fwrite(&data[cur], nonrun_count, 1, fp) < 1) 812 return(-1); 813 cur += nonrun_count; 814 } 815 816 if (run_count >= MIN_RUN_LENGTH) 817 { 818 buf[0] = 128 + run_count; 819 buf[1] = data[beg_run]; 820 if(fwrite(buf, 2, 1, fp) < 1) 821 return(-1); 822 cur += run_count; 823 } 824 } 825 826 return(0); 827 828 #undef MINRUNLENGTH 829 } 830 831 static int rgbe_write_pixels_RLE(FILE *fp, unsigned char *data, 832 int rle, int width, int height) 833 { 834 unsigned char rgbe[4], *buffer; 835 int i, rc = 0; 836 837 if(!rle || ((width < 8) || (width > 0x7fff))) 838 return(rgbe_write_pixels(fp, data, width * height)); 839 840 buffer = (unsigned char *)g_malloc(4 * width); 841 842 while(height-- > 0) 843 { 844 rgbe[0] = 2; 845 rgbe[1] = 2; 846 rgbe[2] = width >> 8; 847 rgbe[3] = width & 0xff; 848 849 if(fwrite(rgbe, sizeof(rgbe), 1, fp) < 1) 850 { 851 g_free(buffer); 852 return(-1); 853 } 854 855 for(i = 0; i < width; ++i) 856 { 857 buffer[i] = data[4 * i]; 858 buffer[i + width] = data[4 * i + 1]; 859 buffer[i + 2 * width] = data[4 * i + 2]; 860 buffer[i + 3 * width] = data[4 * i + 3]; 861 } 862 863 data += 4 * width; 864 865 /* write out each of the four channels separately run length encoded */ 866 /* first red, then green, then blue, then exponent */ 867 for(i = 0; i < 4; ++i) 868 { 869 if((rc = rgbe_write_bytes_RLE(fp, &buffer[i * width], width))) 870 { 871 g_free(buffer); 872 return(rc); 873 } 874 } 875 } 876 877 g_free(buffer); 878 879 return(rc); 880 } 881 882 static GimpPDBStatusType write_rgbe_image(gchar *filename, gint32 imageID, 883 gint32 drawableID) 884 { 885 FILE *fp; 886 GimpDrawable *drawable; 887 GimpImageType drawable_type; 888 GimpPixelRgn rgn; 889 int rc; 890 guchar *pixels; 891 gchar *tmp; 892 893 drawable = gimp_drawable_get(drawableID); 894 drawable_type = gimp_drawable_type(drawableID); 895 gimp_pixel_rgn_init(&rgn, drawable, 0, 0, drawable->width, 896 drawable->height, 0, 0); 897 898 fp = fopen(filename, "wb"); 899 if(fp == 0) 900 { 901 g_message("Error opening %s", filename); 902 return(GIMP_PDB_EXECUTION_ERROR); 903 } 904 905 pixels = g_malloc(drawable->width * drawable->height * 4); 906 gimp_pixel_rgn_get_rect(&rgn, pixels, 0, 0, drawable->width, 907 drawable->height); 908 909 if(g_run_interactive) 910 { 911 tmp = g_strdup_printf("Saving %s:", filename); 912 gimp_progress_init(tmp); 913 g_free(tmp); 914 } 915 916 fprintf(fp, 917 "#?RADIANCE\n" 918 "# %s\n" 919 "SOFTWARE=GIMP HDR tools\n" 920 "FORMAT=32-bit_rle_rgbe\n", 921 g_write_vals.rle ? "RLE compressed" : "Not RLE compressed"); 922 923 if(g_write_vals.writelevels) 924 { 925 fprintf(fp, 926 "EXPOSURE=%f\n" 927 "GAMMA=%f\n", 928 g_write_vals.exposure, g_write_vals.gamma); 929 } 930 931 fprintf(fp, 932 "\n-Y %d +X %d\n", 933 drawable->height, drawable->width); 934 935 rc = rgbe_write_pixels_RLE(fp, pixels, g_write_vals.rle, 936 drawable->width, drawable->height); 937 fclose(fp); 938 939 gimp_drawable_detach(drawable); 940 941 g_free(pixels); 942 943 return(rc ? GIMP_PDB_EXECUTION_ERROR : GIMP_PDB_SUCCESS); 944 } 945 946 static void convert_rgbe_to_rgbdiv8(GimpPreview *preview, 947 GimpDrawable *drawable) 948 { 949 GimpPixelRgn srcrgn, dstrgn; 950 unsigned char *src, *dst, *rgbe; 951 float rgb[3], maxchan, v, range; 952 int sx, sy, x, y, w, h, n, idx = 0; 953 954 range = g_rgbd8_vals.range; 955 956 if(preview) 957 { 958 gimp_preview_get_position(preview, &sx, &sy); 959 gimp_preview_get_size(preview, &w, &h); 960 } 961 else 962 { 963 sx = 0; 964 sy = 0; 965 w = drawable->width; 966 h = drawable->height; 967 } 968 969 n = w * h; 970 dst = g_malloc(n * 4); 971 src = g_malloc(n * 4); 972 973 gimp_pixel_rgn_init(&srcrgn, drawable, sx, sy, w, h, 0, 0); 974 gimp_pixel_rgn_get_rect(&srcrgn, src, sx, sy, w, h); 975 976 if(!preview) 977 gimp_progress_init("Converting to RGBdiv8..."); 978 979 for(y = 0; y < h; ++y) 980 { 981 for(x = 0; x < w; ++x) 982 { 983 rgbe = &src[idx]; 984 if(rgbe[3]) 985 { 986 v = ldexpf(1.0f, rgbe[3] - 136); 987 rgb[0] = (float)rgbe[0] * v; 988 rgb[1] = (float)rgbe[1] * v; 989 rgb[2] = (float)rgbe[2] * v; 990 } 991 else 992 rgb[0] = rgb[1] = rgb[2] = 0; 993 994 maxchan = max(range, max(rgb[0], max(rgb[1], rgb[2]))); 995 996 dst[idx++] = (unsigned char)(255.0f * rgb[0] / maxchan); 997 dst[idx++] = (unsigned char)(255.0f * rgb[1] / maxchan); 998 dst[idx++] = (unsigned char)(255.0f * rgb[2] / maxchan); 999 dst[idx++] = (unsigned char)(255.0f * range / maxchan); 1000 } 1001 1002 if(!preview) 1003 gimp_progress_update((gdouble)y / (gdouble)drawable->height); 1004 } 1005 1006 1007 gimp_pixel_rgn_init(&dstrgn, drawable, sx, sy, w, h, 1008 preview == NULL, 1); 1009 gimp_pixel_rgn_set_rect(&dstrgn, dst, sx, sy, w, h); 1010 1011 if(preview) 1012 { 1013 gimp_drawable_preview_draw_region(GIMP_DRAWABLE_PREVIEW(preview), 1014 &dstrgn); 1015 } 1016 else 1017 { 1018 gimp_progress_update(100); 1019 1020 gimp_drawable_flush(drawable); 1021 gimp_drawable_merge_shadow(drawable->drawable_id, 1); 1022 gimp_drawable_update(drawable->drawable_id, 0, 0, w, h); 1023 } 1024 1025 g_free(src); 1026 g_free(dst); 1027 } 1028 1029 static void tonemap_image(GimpPreview *preview, GimpDrawable *drawable) 1030 { 1031 GimpPixelRgn srcrgn, dstrgn; 1032 unsigned char *src, *dst; 1033 float rgb[3], v; 1034 int sx, sy, x, y, w, h, n, idx = 0; 1035 1036 if(preview) 1037 { 1038 gimp_preview_get_position(preview, &sx, &sy); 1039 gimp_preview_get_size(preview, &w, &h); 1040 } 1041 else 1042 { 1043 sx = 0; 1044 sy = 0; 1045 w = drawable->width; 1046 h = drawable->height; 1047 } 1048 1049 n = w * h; 1050 1051 dst = g_malloc(n * 4); 1052 src = g_malloc(n * 4); 1053 1054 gimp_pixel_rgn_init(&srcrgn, drawable, sx, sy, w, h, 0, 0); 1055 gimp_pixel_rgn_get_rect(&srcrgn, src, sx, sy, w, h); 1056 1057 if(!preview) 1058 gimp_progress_init("Tone mapping image..."); 1059 1060 for(y = 0; y < h; ++y) 1061 { 1062 for(x = 0; x < w; ++x) 1063 { 1064 if(g_tonemap_vals.imgtype == IMAGE_TYPE_RGBE) 1065 { 1066 if(src[idx + 3]) 1067 { 1068 v = ldexpf(1.0f, src[idx + 3] - 136); 1069 rgb[0] = (float)src[idx + 0] * v; 1070 rgb[1] = (float)src[idx + 1] * v; 1071 rgb[2] = (float)src[idx + 2] * v; 1072 } 1073 else 1074 rgb[0] = rgb[1] = rgb[2] = 0; 1075 } 1076 else 1077 { 1078 v = (float)src[idx + 3] / 255.0f; 1079 if(v > 0) 1080 { 1081 rgb[0] = ((float)src[idx + 0] / 255.0f) / v; 1082 rgb[1] = ((float)src[idx + 1] / 255.0f) / v; 1083 rgb[2] = ((float)src[idx + 2] / 255.0f) / v; 1084 } 1085 else 1086 rgb[0] = rgb[1] = rgb[2] = FLT_MAX; 1087 } 1088 1089 /* exposure */ 1090 rgb[0] = 1.0f - expf(-rgb[0] * g_tonemap_vals.exposure); 1091 rgb[1] = 1.0f - expf(-rgb[1] * g_tonemap_vals.exposure); 1092 rgb[2] = 1.0f - expf(-rgb[2] * g_tonemap_vals.exposure); 1093 1094 /* gamma correction */ 1095 rgb[0] = powf(rgb[0], 1.0f / g_tonemap_vals.gamma); 1096 rgb[1] = powf(rgb[1], 1.0f / g_tonemap_vals.gamma); 1097 rgb[2] = powf(rgb[2], 1.0f / g_tonemap_vals.gamma); 1098 1099 rgb[0] = clamp(rgb[0], 0, 1); 1100 rgb[1] = clamp(rgb[1], 0, 1); 1101 rgb[2] = clamp(rgb[2], 0, 1); 1102 1103 dst[idx++] = (unsigned char)(255.0f * rgb[0]); 1104 dst[idx++] = (unsigned char)(255.0f * rgb[1]); 1105 dst[idx++] = (unsigned char)(255.0f * rgb[2]); 1106 dst[idx++] = 255; 1107 } 1108 1109 if(!preview) 1110 gimp_progress_update((gdouble)y / (gdouble)h); 1111 } 1112 1113 gimp_pixel_rgn_init(&dstrgn, drawable, sx, sy, w, h, 1114 preview == NULL, 1); 1115 gimp_pixel_rgn_set_rect(&dstrgn, dst, sx, sy, w, h); 1116 1117 if(preview) 1118 { 1119 gimp_drawable_preview_draw_region(GIMP_DRAWABLE_PREVIEW(preview), 1120 &dstrgn); 1121 } 1122 else 1123 { 1124 gimp_progress_update(100); 1125 1126 gimp_drawable_flush(drawable); 1127 gimp_drawable_merge_shadow(drawable->drawable_id, 1); 1128 gimp_drawable_update(drawable->drawable_id, 0, 0, w, h); 1129 } 1130 1131 g_free(src); 1132 g_free(dst); 1133 } 1134 1135 static void on_spin_changed(GtkWidget *widget, gpointer data) 1136 { 1137 float *val = (float*)data; 1138 *val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); 1139 GimpPreview *preview = g_object_get_data(G_OBJECT(widget), "preview"); 1140 if(preview) 1141 gimp_preview_invalidate(preview); 1142 } 1143 1144 static void on_slider_changed(GtkWidget *widget, gpointer data) 1145 { 1146 float *val = (float*)data; 1147 *val = gtk_range_get_value(GTK_RANGE(widget)); 1148 GimpPreview *preview = g_object_get_data(G_OBJECT(widget), "preview"); 1149 if(preview) 1150 gimp_preview_invalidate(preview); 1151 } 1152 1153 static void on_checkbox_clicked(GtkWidget *widget, gpointer data) 1154 { 1155 int *val = (int*)data; 1156 *val = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); 1157 } 1158 1159 static void dialog_response(GtkWidget *widget, gint response_id, 1160 gpointer data) 1161 { 1162 switch(response_id) 1163 { 1164 case GTK_RESPONSE_OK: 1165 g_runme = 1; 1166 default: 1167 gtk_widget_destroy(widget); 1168 break; 1169 } 1170 } 1171 1172 static int tonemap_dialog(GimpDrawable *drawable) 1173 { 1174 GtkWidget *dlg; 1175 GtkWidget *table; 1176 GtkWidget *label; 1177 GtkObject *adj; 1178 GtkWidget *hbox; 1179 GtkWidget *preview, *exposure_spin, *gamma_spin; 1180 1181 dlg = gimp_dialog_new("Tone map image", PROG_NAME, 1182 0, 0, 0, 0, 1183 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 1184 GTK_STOCK_OK, GTK_RESPONSE_OK, 1185 NULL); 1186 1187 hbox = gtk_hbox_new(0, 8); 1188 gtk_widget_show(hbox); 1189 gtk_container_set_border_width(GTK_CONTAINER(hbox), 8); 1190 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), hbox, 1, 1, 0); 1191 1192 preview = gimp_drawable_preview_new(drawable, &g_tonemap_vals.preview); 1193 gtk_widget_show(preview); 1194 gtk_box_pack_start(GTK_BOX(hbox), preview, 1, 1, 0); 1195 1196 table = gtk_table_new(2, 2, 0); 1197 gtk_widget_show(table); 1198 gtk_box_pack_start(GTK_BOX(hbox), table, 1, 1, 0); 1199 gtk_table_set_row_spacings(GTK_TABLE(table), 8); 1200 gtk_table_set_col_spacings(GTK_TABLE(table), 8); 1201 1202 label = gtk_label_new("Exposure:"); 1203 gtk_widget_show(label); 1204 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); 1205 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0); 1206 1207 adj = gtk_adjustment_new(g_tonemap_vals.exposure, 0, 100, 0.1, 0.5, 1); 1208 exposure_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1); 1209 gtk_widget_show(exposure_spin); 1210 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(exposure_spin), 1211 GTK_UPDATE_IF_VALID); 1212 gtk_table_attach(GTK_TABLE(table), exposure_spin, 1, 2, 0, 1, 1213 GTK_EXPAND | GTK_FILL, 0, 0, 0); 1214 g_object_set_data(G_OBJECT(exposure_spin), "preview", preview); 1215 1216 label = gtk_label_new("Gamma:"); 1217 gtk_widget_show(label); 1218 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); 1219 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0); 1220 1221 adj = gtk_adjustment_new(g_tonemap_vals.gamma, 0, 100, 0.1, 0.5, 1); 1222 gamma_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1); 1223 gtk_widget_show(gamma_spin); 1224 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(gamma_spin), 1225 GTK_UPDATE_IF_VALID); 1226 gtk_table_attach(GTK_TABLE(table), gamma_spin, 1, 2, 1, 2, 1227 GTK_EXPAND | GTK_FILL, 0, 0, 0); 1228 g_object_set_data(G_OBJECT(gamma_spin), "preview", preview); 1229 1230 1231 gtk_signal_connect(GTK_OBJECT(dlg), "response", 1232 GTK_SIGNAL_FUNC(dialog_response), 0); 1233 gtk_signal_connect(GTK_OBJECT(dlg), "destroy", 1234 GTK_SIGNAL_FUNC(gtk_main_quit), 0); 1235 gtk_signal_connect(GTK_OBJECT(preview), "invalidated", 1236 GTK_SIGNAL_FUNC(tonemap_image), 1237 drawable); 1238 gtk_signal_connect(GTK_OBJECT(exposure_spin), "value_changed", 1239 GTK_SIGNAL_FUNC(on_spin_changed), 1240 &g_tonemap_vals.exposure); 1241 gtk_signal_connect(GTK_OBJECT(gamma_spin), "value_changed", 1242 GTK_SIGNAL_FUNC(on_spin_changed), 1243 &g_tonemap_vals.gamma); 1244 1245 gtk_widget_show(dlg); 1246 1247 g_runme = 0; 1248 1249 gtk_main(); 1250 1251 return(g_runme); 1252 } 1253 1254 static int rgbd8_dialog(GimpDrawable *drawable) 1255 { 1256 GtkWidget *dlg; 1257 GtkObject *adj; 1258 GtkWidget *slider; 1259 GtkWidget *vbox; 1260 GtkWidget *table; 1261 GtkWidget *preview; 1262 1263 dlg = gimp_dialog_new("Convert Radiance RGBE to RGBdiv8", PROG_NAME, 1264 0, 0, 0, 0, 1265 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 1266 GTK_STOCK_OK, GTK_RESPONSE_OK, 1267 NULL); 1268 1269 vbox = gtk_vbox_new(0, 0); 1270 gtk_widget_show(vbox); 1271 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); 1272 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), vbox, 1, 1, 0); 1273 1274 table = gtk_table_new(2, 2, 0); 1275 gtk_widget_show(table); 1276 gtk_box_pack_start(GTK_BOX(vbox), table, 1, 1, 0); 1277 gtk_table_set_row_spacings(GTK_TABLE(table), 8); 1278 gtk_table_set_col_spacings(GTK_TABLE(table), 8); 1279 1280 preview = gimp_drawable_preview_new(drawable, &g_rgbd8_vals.preview); 1281 gtk_widget_show(preview); 1282 gtk_table_attach(GTK_TABLE(table), preview, 0, 2, 0, 1, 1283 GTK_EXPAND | GTK_FILL, 0, 0, 0); 1284 1285 adj = gtk_adjustment_new(g_rgbd8_vals.range, 0, 1, 0.01, 0.1, 0); 1286 slider = gtk_hscale_new(GTK_ADJUSTMENT(adj)); 1287 gtk_widget_show(slider); 1288 gtk_scale_set_value_pos(GTK_SCALE(slider), GTK_POS_RIGHT); 1289 gtk_scale_set_digits(GTK_SCALE(slider), 2); 1290 gimp_table_attach_aligned(GTK_TABLE(table), 0, 1, "Range:", 0, 0.5, 1291 slider, 1, 0); 1292 g_object_set_data(G_OBJECT(slider), "preview", preview); 1293 1294 gtk_signal_connect(GTK_OBJECT(dlg), "response", 1295 GTK_SIGNAL_FUNC(dialog_response), 0); 1296 gtk_signal_connect(GTK_OBJECT(dlg), "destroy", 1297 GTK_SIGNAL_FUNC(gtk_main_quit), 0); 1298 gtk_signal_connect(GTK_OBJECT(preview), "invalidated", 1299 GTK_SIGNAL_FUNC(convert_rgbe_to_rgbdiv8), drawable); 1300 gtk_signal_connect(GTK_OBJECT(slider), "value_changed", 1301 GTK_SIGNAL_FUNC(on_slider_changed), 1302 &g_rgbd8_vals.range); 1303 1304 gtk_widget_show(dlg); 1305 1306 g_runme = 0; 1307 1308 gtk_main(); 1309 1310 return(g_runme); 1311 } 1312 1313 static void on_file_levels_checked(GtkWidget *widget, gpointer data) 1314 { 1315 GtkWidget *spin; 1316 int val = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); 1317 1318 *((int *)data) = val; 1319 1320 spin = g_object_get_data(G_OBJECT(widget), "exposure_spin"); 1321 gtk_widget_set_sensitive(spin, !val); 1322 spin = g_object_get_data(G_OBJECT(widget), "gamma_spin"); 1323 gtk_widget_set_sensitive(spin, !val); 1324 } 1325 1326 static int read_rgbe_dialog(void) 1327 { 1328 GtkWidget *dlg; 1329 GtkWidget *table; 1330 GtkWidget *label; 1331 GtkObject *adj; 1332 GtkWidget *tmchk, *uflchk, *exposure_spin, *gamma_spin; 1333 1334 dlg = gimp_dialog_new("Load RGBE image", PROG_NAME, 1335 0, 0, 0, 0, 1336 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 1337 GTK_STOCK_OK, GTK_RESPONSE_OK, 1338 NULL); 1339 1340 table = gtk_table_new(4, 2, 0); 1341 gtk_widget_show(table); 1342 gtk_container_set_border_width(GTK_CONTAINER(table), 8); 1343 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), table, 1, 1, 0); 1344 gtk_table_set_row_spacings(GTK_TABLE(table), 8); 1345 gtk_table_set_col_spacings(GTK_TABLE(table), 8); 1346 1347 tmchk = gtk_check_button_new_with_label("Tone map image"); 1348 gtk_widget_show(tmchk); 1349 gtk_table_attach(GTK_TABLE(table), tmchk, 0, 2, 0, 1, 1350 GTK_EXPAND | GTK_FILL, 0, 0, 0); 1351 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tmchk), 1352 g_tonemap_vals.tonemap); 1353 1354 uflchk = gtk_check_button_new_with_label("Use file levels"); 1355 gtk_widget_show(uflchk); 1356 gtk_table_attach(GTK_TABLE(table), uflchk, 0, 2, 1, 2, 1357 GTK_EXPAND | GTK_FILL, 0, 0, 0); 1358 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uflchk), 1359 g_tonemap_vals.usefilelevels); 1360 1361 label = gtk_label_new("Exposure:"); 1362 gtk_widget_show(label); 1363 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, 0, 0, 0); 1364 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); 1365 1366 adj = gtk_adjustment_new(g_tonemap_vals.exposure, 0, 100, 0.1, 0.5, 0.1); 1367 exposure_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1); 1368 gtk_widget_show(exposure_spin); 1369 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(exposure_spin), 1370 GTK_UPDATE_IF_VALID); 1371 gtk_table_attach(GTK_TABLE(table), exposure_spin, 1, 2, 2, 3, 1372 GTK_EXPAND | GTK_FILL, 0, 0, 0); 1373 gtk_widget_set_sensitive(exposure_spin, !g_tonemap_vals.usefilelevels); 1374 1375 label = gtk_label_new("Gamma:"); 1376 gtk_widget_show(label); 1377 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, 0, 0, 0); 1378 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); 1379 1380 adj = gtk_adjustment_new(g_tonemap_vals.gamma, 0, 100, 0.1, 0.5, 0.1); 1381 gamma_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1); 1382 gtk_widget_show(gamma_spin); 1383 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(gamma_spin), 1384 GTK_UPDATE_IF_VALID); 1385 gtk_table_attach(GTK_TABLE(table), gamma_spin, 1, 2, 3, 4, 1386 GTK_EXPAND | GTK_FILL, 0, 0, 0); 1387 gtk_widget_set_sensitive(gamma_spin, !g_tonemap_vals.usefilelevels); 1388 1389 g_object_set_data(G_OBJECT(uflchk), "exposure_spin", exposure_spin); 1390 g_object_set_data(G_OBJECT(uflchk), "gamma_spin", gamma_spin); 1391 1392 gtk_signal_connect(GTK_OBJECT(dlg), "response", 1393 GTK_SIGNAL_FUNC(dialog_response), 0); 1394 gtk_signal_connect(GTK_OBJECT(dlg), "destroy", 1395 GTK_SIGNAL_FUNC(gtk_main_quit), 0); 1396 gtk_signal_connect(GTK_OBJECT(tmchk), "clicked", 1397 GTK_SIGNAL_FUNC(on_checkbox_clicked), 1398 &g_tonemap_vals.tonemap); 1399 gtk_signal_connect(GTK_OBJECT(uflchk), "clicked", 1400 GTK_SIGNAL_FUNC(on_file_levels_checked), 1401 &g_tonemap_vals.usefilelevels); 1402 gtk_signal_connect(GTK_OBJECT(exposure_spin), "value_changed", 1403 GTK_SIGNAL_FUNC(on_spin_changed), 1404 &g_tonemap_vals.exposure); 1405 gtk_signal_connect(GTK_OBJECT(gamma_spin), "value_changed", 1406 GTK_SIGNAL_FUNC(on_spin_changed), 1407 &g_tonemap_vals.gamma); 1408 1409 gtk_widget_show(dlg); 1410 1411 g_runme = 0; 1412 1413 gtk_main(); 1414 1415 return(g_runme); 1416 } 1417 1418 static void on_write_levels_checked(GtkWidget *widget, gpointer data) 1419 { 1420 GtkWidget *spin; 1421 int val = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); 1422 1423 *((int *)data) = val; 1424 1425 spin = g_object_get_data(G_OBJECT(widget), "exposure_spin"); 1426 gtk_widget_set_sensitive(spin, val); 1427 spin = g_object_get_data(G_OBJECT(widget), "gamma_spin"); 1428 gtk_widget_set_sensitive(spin, val); 1429 } 1430 1431 static int write_rgbe_dialog(void) 1432 { 1433 GtkWidget *dlg; 1434 GtkWidget *table; 1435 GtkWidget *label; 1436 GtkObject *adj; 1437 GtkWidget *rlechk, *wlchk, *exposure_spin, *gamma_spin; 1438 1439 dlg = gimp_dialog_new("Save RGBE image", PROG_NAME, 1440 0, 0, 0, 0, 1441 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 1442 GTK_STOCK_OK, GTK_RESPONSE_OK, 1443 NULL); 1444 1445 table = gtk_table_new(4, 2, 0); 1446 gtk_widget_show(table); 1447 gtk_container_set_border_width(GTK_CONTAINER(table), 8); 1448 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), table, 1, 1, 0); 1449 gtk_table_set_row_spacings(GTK_TABLE(table), 8); 1450 gtk_table_set_col_spacings(GTK_TABLE(table), 8); 1451 1452 rlechk = gtk_check_button_new_with_label("RLE compression"); 1453 gtk_widget_show(rlechk); 1454 gtk_table_attach(GTK_TABLE(table), rlechk, 0, 2, 0, 1, 1455 GTK_EXPAND | GTK_FILL, 0, 0, 0); 1456 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rlechk), 1457 g_write_vals.rle); 1458 1459 wlchk = gtk_check_button_new_with_label("Write exposure and gamma"); 1460 gtk_widget_show(wlchk); 1461 gtk_table_attach(GTK_TABLE(table), wlchk, 0, 2, 1, 2, 1462 GTK_EXPAND | GTK_FILL, 0, 0, 0); 1463 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wlchk), 1464 g_write_vals.writelevels); 1465 1466 label = gtk_label_new("Exposure:"); 1467 gtk_widget_show(label); 1468 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, 0, 0, 0); 1469 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); 1470 1471 adj = gtk_adjustment_new(g_write_vals.exposure, 0, 100, 0.1, 0.5, 0.1); 1472 exposure_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1); 1473 gtk_widget_show(exposure_spin); 1474 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(exposure_spin), 1475 GTK_UPDATE_IF_VALID); 1476 gtk_table_attach(GTK_TABLE(table), exposure_spin, 1, 2, 2, 3, 1477 GTK_EXPAND | GTK_FILL, 0, 0, 0); 1478 gtk_widget_set_sensitive(exposure_spin, g_write_vals.writelevels); 1479 1480 label = gtk_label_new("Gamma:"); 1481 gtk_widget_show(label); 1482 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, 0, 0, 0); 1483 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); 1484 1485 adj = gtk_adjustment_new(g_write_vals.gamma, 0, 100, 0.1, 0.5, 0.1); 1486 gamma_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1); 1487 gtk_widget_show(gamma_spin); 1488 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(gamma_spin), 1489 GTK_UPDATE_IF_VALID); 1490 gtk_table_attach(GTK_TABLE(table), gamma_spin, 1, 2, 3, 4, 1491 GTK_EXPAND | GTK_FILL, 0, 0, 0); 1492 gtk_widget_set_sensitive(gamma_spin, g_write_vals.writelevels); 1493 1494 g_object_set_data(G_OBJECT(wlchk), "exposure_spin", exposure_spin); 1495 g_object_set_data(G_OBJECT(wlchk), "gamma_spin", gamma_spin); 1496 1497 gtk_signal_connect(GTK_OBJECT(dlg), "response", 1498 GTK_SIGNAL_FUNC(dialog_response), 0); 1499 gtk_signal_connect(GTK_OBJECT(dlg), "destroy", 1500 GTK_SIGNAL_FUNC(gtk_main_quit), 0); 1501 gtk_signal_connect(GTK_OBJECT(rlechk), "clicked", 1502 GTK_SIGNAL_FUNC(on_checkbox_clicked), 1503 &g_write_vals.rle); 1504 gtk_signal_connect(GTK_OBJECT(wlchk), "clicked", 1505 GTK_SIGNAL_FUNC(on_write_levels_checked), 1506 &g_write_vals.writelevels); 1507 gtk_signal_connect(GTK_OBJECT(exposure_spin), "value_changed", 1508 GTK_SIGNAL_FUNC(on_spin_changed), 1509 &g_write_vals.exposure); 1510 gtk_signal_connect(GTK_OBJECT(gamma_spin), "value_changed", 1511 GTK_SIGNAL_FUNC(on_spin_changed), 1512 &g_write_vals.gamma); 1513 1514 gtk_widget_show(dlg); 1515 1516 g_runme = 0; 1517 1518 gtk_main(); 1519 1520 return(g_runme); 1521 }
| ViewVC Help | |
| Powered by ViewVC 1.0.4 |