/* * This is a plug-in for the GIMP. * * Copyright (C) 1996 Torsten Martinsen * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. * * $Id: ripple.c,v 1.7 1996/08/22 10:20:57 torsten Exp $ * * @(GIMP) = * @(GIMP_DEP) = * @(GIMP_OBJ) = * @(GIMP_LIB) = * @(GIMP_AUTHOR) = * @(GIMP_EMAIL) = * @(GIMP_DESC) = * @(GIMP_VERSION) = <$Revision: 1.7 $> * @(GIMP_URL) = */ /* * This plug-in displaces each row of the image according to a sine function, * a triangular function, or a random function. * (You can displace the columns by rotating the image * 90 degrees before applying the filter). */ #include #include #include #include "gimp.h" /* * Change this if your system doesn't have random(). */ #if 1 #define RANDOM random #define SRANDOM srandom #else #define RANDOM rand #define SRANDOM srand #endif #define NTYPES 3 typedef struct { long type[NTYPES]; long period; long amplitude; } ripple_params_t; static void scale_callback(int, void *, void *); static void ok_callback(int, void *, void *); static void cancel_callback(int, void *, void *); static void radio_callback(int item_ID, void *client_data, void *call_data); static void ripple(Image input, Image output); static int dialog_ID; static ripple_params_t params = { {1, 0, 0}, 8, 5 }; int main(int argc, char **argv) { Image input, output; void *data; int group_ID, row_ID, frame_ID, scalep_ID, scalea_ID, i, ID; static char * rb_label[NTYPES] = { "Sine", "Triangle", "Random" }; if (gimp_init(argc, argv)) { output = 0; data = gimp_get_params(); if (data) params = *((ripple_params_t *) data); input = gimp_get_input_image(0); dialog_ID = gimp_new_dialog("Ripple"); group_ID = gimp_new_row_group(dialog_ID, DEFAULT, NORMAL, ""); frame_ID = gimp_new_frame(dialog_ID, group_ID, "Waveform"); row_ID = gimp_new_row_group(dialog_ID, frame_ID, RADIO, ""); for (i = 0; i < NTYPES; ++i) { ID = gimp_new_radio_button(dialog_ID, row_ID, rb_label[i]); gimp_add_callback(dialog_ID, ID, radio_callback, ¶ms.type[i]); gimp_change_item (dialog_ID, ID, sizeof (long), ¶ms.type[i]); } row_ID = gimp_new_row_group(dialog_ID, group_ID, NORMAL, ""); gimp_new_label(dialog_ID, row_ID, "Period"); scalep_ID = gimp_new_scale(dialog_ID, row_ID, 1, 200, params.period, 0); gimp_add_callback(dialog_ID, scalep_ID, scale_callback, ¶ms.period); row_ID = gimp_new_row_group(dialog_ID, group_ID, NORMAL, ""); gimp_new_label(dialog_ID, row_ID, "Amplitude"); scalea_ID = gimp_new_scale(dialog_ID, group_ID, 1, 100, params.amplitude, 0); gimp_add_callback(dialog_ID, scalea_ID, scale_callback, ¶ms.amplitude); gimp_add_callback(dialog_ID, gimp_ok_item_id(dialog_ID), ok_callback, 0); gimp_add_callback(dialog_ID, gimp_cancel_item_id(dialog_ID), cancel_callback, 0); if (gimp_show_dialog(dialog_ID)) { gimp_set_params(sizeof(ripple_params_t), ¶ms); output = gimp_get_output_image(0); if (input && output) { gimp_init_progress("Ripple"); if (gimp_image_type(input) == INDEXED_IMAGE) gimp_set_image_colors(output, gimp_image_cmap(input), gimp_image_colors(input)); gimp_display_image(output); ripple(input, output); gimp_update_image(output); } } if (input) gimp_free_image(input); if (output) gimp_free_image(output); gimp_quit(); } return 0; } static void ripple(Image input, Image output) { long width, height; long channels, rowstride; unsigned char *src_row, *dest_row; unsigned char *src, *dest; short row, col; int x1, y1, x2, y2; int shift, i, nc, alpha; gimp_image_area(input, &x1, &y1, &x2, &y2); width = gimp_image_width(input); height = gimp_image_height(input); channels = gimp_image_channels(input); rowstride = width * channels; alpha = (channels == 2) || (channels == 4); nc = channels-alpha; src_row = gimp_image_data(input); dest_row = gimp_image_data(output); src_row += rowstride * y1 + x1 * channels; dest_row += rowstride * y1 + x1 * channels; if (params.type[2]) SRANDOM(time(NULL)); for (row = y1; row < y2; row++) { src = src_row; dest = dest_row; if (params.type[0]) { /* sine */ shift = params.amplitude * sin((row-y1)*2.0*M_PI/params.period); } else if (params.type[1]) { /* triangle */ shift = ((row-y1) % params.period)*2*params.amplitude/params.period; if (shift > params.amplitude) shift = 2*params.amplitude - shift; } else { /* random */ shift = (RANDOM() % (2*params.amplitude+1)) - params.amplitude; } if (shift < 0) { shift = -shift; src += shift * channels; if ((x2 - shift) > width) { for (col = x1; col < x2 - shift; col++) { for (i = 0; i < nc; i++) *dest++ = *src++; dest += alpha; src += alpha; } src -= channels; for (; col < x2; col++) { for (i = 0; i < nc; i++) *dest++ = src[i]; dest += alpha; } } else { for (col = x1; col < x2; col++) { for (i = 0; i < nc; i++) *dest++ = *src++; dest += alpha; src += alpha; } } } else { for (col = x1; col < x1 + shift; col++) { for (i = 0; i < nc; i++) *dest++ = src[i]; dest += alpha; } for (; col < x2; col++) { for (i = 0; i < nc; i++) *dest++ = *src++; dest += alpha; src += alpha; } } src_row += rowstride; dest_row += rowstride; if ((row % 5) == 0) gimp_do_progress(row, y2-y1); } /* Copy alpha channel */ if (!alpha) return; src_row = gimp_image_data(input) + rowstride * y1 + (x1+1) * channels - 1; dest_row = gimp_image_data(output) + rowstride * y1 + (x1+1) * channels - 1; for (row = y1; row < y2; ++row) { src = src_row; dest = dest_row; for (col = x1; col < x2; ++col) { *dest = *src; dest += channels; src += channels; } dest_row += rowstride; src_row += rowstride; } } static void scale_callback(int item_ID, void *client_data, void *call_data) { *((long *) client_data) = *((long *) call_data); } static void ok_callback(int item_ID, void *client_data, void *call_data) { gimp_close_dialog(dialog_ID, 1); } static void cancel_callback(int item_ID, void *client_data, void *call_data) { gimp_close_dialog(dialog_ID, 0); } static void radio_callback(int item_ID, void *client_data, void *call_data) { *((long *) client_data) = *((long *) call_data); }