/* vigneting.c * Make or remove Wigneting plugin for Gimp 2.x * Copyright (C) 2006 Luc courtrai * * structure of program is copie of * hpf.c * A high pass filter plugin for Gimp 2.x * Smooths overall brightness of an image * Copyright (C) 2004 David Hodson hodsond@ozemail.com.au * * tank David */ #include #include #include #include #include #define PLUGIN_NAME "Vigneting" #define PLUGIN_TITLE "Vigneting" static void query (void); static void run (const char *name, int n_params, const GimpParam * param, int *nreturn_vals, GimpParam ** return_vals); // parametre dialogue typedef struct { int radius; int brightness; } ProcParams; //valeur par defaut static ProcParams procParams = { 80, 40 }; static gint32 do_it = FALSE; static void start(gint32 image_id, GimpDrawable * drawable); static void procDialog(); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run /* run_proc */ }; MAIN() static void query (void) { static GimpParamDef args[] = { {GIMP_PDB_INT32, "run_mode", "Interactive"}, {GIMP_PDB_IMAGE, "image", "Input image"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable"}, {GIMP_PDB_INT32, "radius", "Start radius" }, {GIMP_PDB_INT32, "brightness", "Average brightness" }, }; static GimpParamDef *return_vals = NULL; static guint nargs = sizeof(args) / sizeof(args[0]); static guint nreturn_vals = 0; gimp_install_procedure ( PLUGIN_NAME, "Vignetting", "Make or remove wigneting of photo", "Luc Courtrai", "Luc Courtrai", "2006", "/Filters/Light Effets/Vignetting...", "GRAY*,RGB*", GIMP_PLUGIN, nargs, nreturn_vals, args, return_vals ); } static void run (const char *name, int n_params, const GimpParam * param, int *nreturn_vals, GimpParam ** return_vals) { static GimpParam values[1]; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; GimpDrawable *drawable; gint32 image_id; *nreturn_vals = 1; *return_vals = values; run_mode = param[0].data.d_int32; image_id = param[1].data.d_image; drawable = gimp_drawable_get (param[2].data.d_drawable); switch (run_mode) { case GIMP_RUN_INTERACTIVE: gimp_get_data(PLUGIN_NAME, &procParams); procDialog(); if (!do_it) { return; } break; case GIMP_RUN_NONINTERACTIVE: if (n_params != 5) status = GIMP_PDB_CALLING_ERROR; if (status == GIMP_PDB_SUCCESS) { procParams.radius = param[3].data.d_int32; procParams.brightness = param[4].data.d_int32; } break; case GIMP_RUN_WITH_LAST_VALS: gimp_get_data(PLUGIN_NAME, &procParams); break; default: break; } start (image_id, drawable); if (run_mode != GIMP_RUN_NONINTERACTIVE) gimp_displays_flush(); if (run_mode == GIMP_RUN_INTERACTIVE) gimp_set_data(PLUGIN_NAME, &procParams, sizeof(ProcParams)); values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; } void start(gint32 image_id, GimpDrawable* drawable) { float progress; float progressStep; int progressChunk; gint32 x1, y1, x2, y2; GimpPixelRgn srcRegion, dstRegion; guchar* pr; int x, y; gint32 centreX= drawable->width /2; gint32 centreY= drawable->height /2; gint32 distanceMax= sqrt( (drawable->width - centreX)* (drawable->width - centreX) + ( drawable->height - centreY)* (drawable->height - centreY)); float start=procParams.radius/100.; int force=(procParams.brightness*255)/100; gimp_drawable_mask_bounds(drawable->drawable_id, &x1, &y1, &x2, &y2); /* Initialize progress */ progress = 0; progressStep = 1.0 / ((x2 - x1) * (y2 - y1)); progressChunk = 0; gimp_progress_init(PLUGIN_TITLE); gimp_pixel_rgn_init(&srcRegion, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); gimp_pixel_rgn_init(&dstRegion, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE); pr = gimp_pixel_rgns_register (2, &srcRegion, &dstRegion); for ( ; pr != 0; pr = gimp_pixel_rgns_process(pr)) { guchar* src = srcRegion.data; // guchar* blur = blurRegion.data; guchar* dst = dstRegion.data; for (y = 0; y < srcRegion.h; y++) { guchar* s = src; // guchar* b = blur; guchar* d = dst; for (x = 0; x < srcRegion.w; x++) { //calcul de la distance par rapport au centre gint32 distance= sqrt( ((srcRegion.x + x) - centreX)* ((srcRegion.x + x) - centreX) + ((srcRegion.y + y) - centreY)* ((srcRegion.y + y) - centreY)); if (distance < distanceMax* start) { memcpy(d,s,srcRegion.bpp); }else{ int newR, newG, newB; float coef = (distance -(distanceMax *start)) / (float)(distanceMax *(1-start)); switch (srcRegion.bpp) { case 1 : // NB newR = s[0]- force*coef; d[0] = (newR < 0) ? 0 : (newR > 255) ? 255 : newR; break; case 2 : newR = s[0]- force*coef; d[0] = (newR < 0) ? 0 : (newR > 255) ? 255 : newR; d[1] = s[1]; break; case 3: newR = s[0]- force*coef; d[0] = (newR < 0) ? 0 : (newR > 255) ? 255 : newR; newG = s[1]- force*coef; d[1] = (newG < 0) ? 0 : (newG > 255) ? 255 : newG; newB = s[2]- force*coef; d[2] = (newB < 0) ? 0 : (newB > 255) ? 255 : newB; break; case 4: newR = s[0]- force*coef; d[0] = (newR < 0) ? 0 : (newR > 255) ? 255 : newR; newG = s[1]- force*coef; d[1] = (newG < 0) ? 0 : (newG > 255) ? 255 : newG; newB = s[2]- force*coef; d[2] = (newB < 0) ? 0 : (newB > 255) ? 255 : newB; d[3]=s[3]; } } s += srcRegion.bpp; d += dstRegion.bpp; } src += srcRegion.rowstride; dst += dstRegion.rowstride; } progress += progressStep * srcRegion.w * srcRegion.h; ++progressChunk; if (progressChunk == 16) { gimp_progress_update(progress); progressChunk = 0; } } gimp_drawable_flush(drawable); gimp_drawable_merge_shadow(drawable->drawable_id, TRUE); gimp_drawable_update(drawable->drawable_id, x1, y1, x2 - x1, y2 - y1); gimp_displays_flush(); gimp_drawable_detach(drawable); } static void adjustmentChanged(GtkAdjustment *adjust, gpointer data) { int* param = (int*)data; *param = adjust->value; } static GtkAdjustment* addControl(GtkWidget* vbox, const char* name, int* data, int min, int max) { GtkWidget* label; GtkWidget* hbox; GtkWidget* hbox2; GtkWidget* slider; GtkWidget* spinner; GtkAdjustment* adjustment; gint width; label = gtk_label_new(name); adjustment = GTK_ADJUSTMENT(gtk_adjustment_new(*data, min, max, 1, 1, 0)); slider = gtk_hscale_new(adjustment); gtk_scale_set_digits(GTK_SCALE(slider), 0); gtk_scale_set_draw_value(GTK_SCALE(slider), FALSE); spinner = gtk_spin_button_new(adjustment, 0.0, 0); /* Need sensible width for value display */ /* Add a small amount to accommodate the arrows */ /* Of course, this should be done automagically */ width = gdk_string_width(gtk_style_get_font(gtk_widget_get_style(spinner)), "-100.0") + 25; gtk_widget_set_usize(GTK_WIDGET(spinner), width, 0); hbox = gtk_hbox_new(TRUE, 2); hbox2 = gtk_hbox_new(TRUE, 2); gtk_box_pack_start(GTK_BOX(hbox2), label, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox2), spinner, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), hbox2, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), slider, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(adjustment), "value_changed", GTK_SIGNAL_FUNC(adjustmentChanged), (gpointer)data); gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, FALSE, 0); return adjustment; } static void procDialog() { GtkWidget* dialog; GtkWidget* vbox; int usesPreview = FALSE; GtkDialogFlags flags = (GtkDialogFlags)0; gimp_ui_init(PLUGIN_NAME, usesPreview); dialog = gimp_dialog_new( PLUGIN_TITLE, PLUGIN_NAME, 0, flags, 0, 0, GTK_STOCK_QUIT, 0, GTK_STOCK_OK, 1, NULL); vbox = GTK_DIALOG(dialog)->vbox; addControl(vbox, "Radius start %", &procParams.radius, 0, 100); addControl(vbox, "Darkness", &procParams.brightness, -100, 100); gtk_widget_show_all(dialog); if (gimp_dialog_run(GIMP_DIALOG(dialog))) { do_it = TRUE; } }