/* Interpolate/Extrapolate 1.01 --- image filter plug-in for The Gimp * Copyright (C) 1996 Federico Mena Quintero * * You can contact me at quartic@polloux.fciencias.unam.mx * You can contact the original The Gimp authors at gimp@xcf.berkeley.edu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include "gimp.h" /* Useful macros */ #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define CLAMP(a, x, b) (((x) <= (a)) ? (a) : (((x) <= (b)) ? (x) : (b))) #ifndef _AIX typedef unsigned char uchar; #endif /***** Local functions *****/ static void image_menu_callback(int item_id, void *client_data, void *call_data); static void double_callback(int item_id, void *client_data, void *call_data); static void ok_callback(int item_id, void *client_data, void *call_data); static void cancel_callback(int item_id, void *client_data, void *call_data); static void do_interpolate(Image img1, Image img2, double value); /***** Local vars *****/ static char *prog_name; static int dialog_id; /***** Functions *****/ /*****/ int main(int argc, char **argv) { Image img1, img2; int img1_menu_id, img2_menu_id; int value_id; int group_id, temp_id; char buf[100]; long img1_id, img2_id; double value; /* Save program name */ prog_name = argv[0]; /* Initialize filter and continue if success */ if (!gimp_init(argc, argv)) return 0; img1_id = img2_id = 0; value = 0.0; dialog_id = gimp_new_dialog("Interpolate/Extrapolate"); group_id = gimp_new_row_group(dialog_id, DEFAULT, NORMAL, ""); img1_menu_id = gimp_new_image_menu(dialog_id, group_id, IMAGE_CONSTRAIN_RGB | IMAGE_CONSTRAIN_GRAY, "First Image"); gimp_add_callback(dialog_id, img1_menu_id, image_menu_callback, &img1_id); img2_menu_id = gimp_new_image_menu(dialog_id, group_id, IMAGE_CONSTRAIN_RGB | IMAGE_CONSTRAIN_GRAY, "Second Image"); gimp_add_callback(dialog_id, img2_menu_id, image_menu_callback, &img2_id); temp_id = gimp_new_column_group(dialog_id, group_id, NORMAL, ""); gimp_new_label(dialog_id, temp_id, "Amount of first image:"); sprintf(buf, "%0.3f", value); value_id = gimp_new_text(dialog_id, temp_id, buf); gimp_add_callback(dialog_id, value_id, double_callback, &value); gimp_add_callback(dialog_id, gimp_ok_item_id(dialog_id), ok_callback, NULL); gimp_add_callback(dialog_id, gimp_cancel_item_id(dialog_id), cancel_callback, NULL); if (gimp_show_dialog(dialog_id)) { img1 = gimp_get_input_image(img1_id); if (img2_id != img1_id) img2 = gimp_get_input_image(img2_id); else img2 = img1; if (img1 && img2) { gimp_init_progress("Interpolate/Extrapolate"); do_interpolate(img1, img2, value); } /* if */ if (img1) gimp_free_image(img1); if (img2 && (img1 != img2)) gimp_free_image(img2); } /* if */ gimp_quit(); return 0; } /* main */ /*****/ static void image_menu_callback(int item_id, void *client_data, void *call_data) { *((long *) client_data) = *((long *) call_data); } /* image_menu_callback */ /*****/ static void double_callback(int item_id, void *client_data, void *call_data) { *((double *) client_data) = atof(call_data); } /* double_callback */ /*****/ static void ok_callback(int item_id, void *client_data, void *call_data) { gimp_close_dialog(dialog_id, 1); } /* ok_callback */ /*****/ static void cancel_callback(int item_id, void *client_data, void *call_data) { gimp_close_dialog(dialog_id, 0); } /* cancel_callback */ /*****/ static void do_interpolate(Image img1, Image img2, double value) { Image img_dest; ImageType dest_type; long img1_channels, img2_channels, dest_channels; long width, height; uchar *src1, *src2, *dest; uchar p1[3], p2[3]; double v; int x, y, k; src1 = gimp_image_data(img1); src2 = gimp_image_data(img2); width = gimp_image_width(img1); height = gimp_image_height(img1); img1_channels = gimp_image_channels(img1); img2_channels = gimp_image_channels(img2); dest_channels = MAX(img1_channels, img2_channels); if ((gimp_image_type(img1) == RGB_IMAGE) || (gimp_image_type(img2) == RGB_IMAGE)) dest_type = RGB_IMAGE; else dest_type = GRAY_IMAGE; img_dest = gimp_new_image(0, width, height, dest_type); dest = gimp_image_data(img_dest); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { /* Fetch and (if necessary) duplicate pixel from first image */ for (k = 0; k < img1_channels; k++) p1[k] = *src1++; if (img1_channels < img2_channels) for (k = 1; k < img2_channels; k++) p1[k] = p1[0]; /* Fetch and (if necessary) duplicate pixel from second image */ for (k = 0; k < img2_channels; k++) p2[k] = *src2++; if (img2_channels < img1_channels) for (k = 1; k < img1_channels; k++) p2[k] = p2[0]; /* Interpolate! */ for (k = 0; k < dest_channels; k++) { v = value * p1[k] + (1.0 - value) * p2[k]; *dest++ = CLAMP(0, v, 255); } /* for */ } /* for */ if (y % 64 == 0) gimp_do_progress(y, height); } /* for */ gimp_display_image(img_dest); gimp_update_image(img_dest); gimp_free_image(img_dest); } /* do_interpolate */