home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / max_rgb.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-01  |  14.2 KB  |  538 lines

  1. /* max_rgb.c -- This is a plug-in for the GIMP (1.0's API)
  2.  * Author: Shuji Narazaki <narazaki@InetQ.or.jp>
  3.  * Time-stamp: <2000-02-08 16:26:24 yasuhiro>
  4.  * Version: 0.35
  5.  *
  6.  * Copyright (C) 1997 Shuji Narazaki <narazaki@InetQ.or.jp>
  7.  *
  8.  * May 2000 - tim copperfield [timecop@japan.co.jp]
  9.  *
  10.  * Added a preview mode.  After adding preview mode realised just exactly
  11.  * how useless this plugin is :)
  12.  *
  13.  * This program is free software; you can redistribute it and/or modify
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2 of the License, or
  16.  * (at your option) any later version.
  17.  *
  18.  * This program is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  * GNU General Public License for more details.
  22.  *
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with this program; if not, write to the Free Software
  25.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  26.  */
  27.  
  28. #include "config.h"
  29.  
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33.  
  34. #include <gtk/gtk.h>
  35.  
  36. #include <libgimp/gimp.h>
  37. #include <libgimp/gimpui.h>
  38.  
  39. #include "libgimp/stdplugins-intl.h"
  40.  
  41.  
  42. /* Replace them with the right ones */
  43. #define    PLUG_IN_NAME         "plug_in_max_rgb"
  44. #define SHORT_NAME         "max_rgb"
  45. #define PROGRESS_UPDATE_NUM  100
  46. #define PREVIEW_SIZE         128 
  47.  
  48. static void    query    (void);
  49. static void    run    (gchar      *name,
  50.              gint        nparams,
  51.              GimpParam  *param,
  52.              gint       *nreturn_vals,
  53.              GimpParam **return_vals);
  54.  
  55. static void        fill_preview_with_thumb (GtkWidget    *preview_widget, 
  56.                         gint32        drawable_id);
  57. static GtkWidget  *preview_widget          (GimpDrawable *drawable);
  58.  
  59. static GimpPDBStatusType main_function     (GimpDrawable *drawable, 
  60.                         gboolean      preview_mode);
  61.  
  62. static gint       dialog         (GimpDrawable *drawable);
  63. static void        ok_callback    (GtkWidget    *widget,
  64.                    gpointer      data);
  65. static void        radio_callback (GtkWidget    *widget, 
  66.                    gpointer      data);
  67.  
  68.  
  69. GimpPlugInInfo PLUG_IN_INFO =
  70. {
  71.   NULL,  /* init_proc  */
  72.   NULL,  /* quit_proc  */
  73.   query, /* query_proc */
  74.   run,   /* run_proc   */
  75. };
  76.  
  77. enum
  78. {
  79.   MIN_CHANNELS = 0,
  80.   MAX_CHANNELS = 1
  81. };
  82.  
  83. typedef struct
  84. {
  85.   gint max_p;  /* gint, gdouble, and so on */
  86. } ValueType;
  87.  
  88. typedef struct 
  89. {
  90.   gint run;
  91. } Interface;
  92.  
  93. static ValueType pvals = 
  94. {
  95.   MAX_CHANNELS
  96. };
  97.  
  98. static Interface interface =
  99. {
  100.   FALSE
  101. };
  102.  
  103. static guchar *preview_bits;
  104. static GtkWidget *preview;
  105.  
  106. MAIN ()
  107.  
  108. static void
  109. query (void)
  110. {
  111.   static GimpParamDef args [] =
  112.   {
  113.     { GIMP_PDB_INT32,    "run_mode", "Interactive, non-interactive"},
  114.     { GIMP_PDB_IMAGE,    "image",    "Input image (not used)"},
  115.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable"},
  116.     { GIMP_PDB_INT32,    "max_p",    "1 for maximizing, 0 for minimizing"}
  117.   };
  118.   static gint nargs = sizeof (args) / sizeof (args[0]);
  119.  
  120.   gimp_install_procedure (PLUG_IN_NAME,
  121.               "Return an image in which each pixel holds only "
  122.               "the channel that has the maximum value in three "
  123.               "(red, green, blue) channels, and other channels "
  124.               "are zero-cleared",
  125.               "the help is not yet written for this plug-in since none is needed.",
  126.               "Shuji Narazaki (narazaki@InetQ.or.jp)",
  127.               "Shuji Narazaki",
  128.               "May 2000",
  129.                           N_("<Image>/Filters/Colors/Max RGB..."),
  130.               "RGB*",
  131.               GIMP_PLUGIN,
  132.               nargs, 0,
  133.               args, NULL);
  134. }
  135.  
  136. static void
  137. run (gchar      *name,
  138.      gint        nparams,
  139.      GimpParam  *param,
  140.      gint       *nreturn_vals,
  141.      GimpParam **return_vals)
  142. {
  143.   GimpDrawable    *drawable;
  144.   static GimpParam    values[1];
  145.   GimpPDBStatusType    status = GIMP_PDB_EXECUTION_ERROR;
  146.   GimpRunModeType    run_mode;
  147.   
  148.   run_mode = param[0].data.d_int32;
  149.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  150.  
  151.   *nreturn_vals = 1;
  152.   *return_vals = values;
  153.   
  154.   values[0].type = GIMP_PDB_STATUS;
  155.   values[0].data.d_status = status;
  156.  
  157.   switch (run_mode)
  158.     {
  159.     case GIMP_RUN_INTERACTIVE:
  160.       INIT_I18N_UI();
  161.       gimp_get_data (PLUG_IN_NAME, &pvals);
  162.       /* Since a channel might be selected, we must check wheter RGB or not. */
  163.       if (!gimp_drawable_is_rgb (drawable->id))
  164.     {
  165.       g_message (_("Max RGB: Can only operate on RGB drawables."));
  166.       return;
  167.     }
  168.       if (! dialog (drawable))
  169.     return;
  170.       break;
  171.     case GIMP_RUN_NONINTERACTIVE:
  172.       INIT_I18N();
  173.       /* You must copy the values of parameters to pvals or dialog variables. */
  174.       break;
  175.     case GIMP_RUN_WITH_LAST_VALS:
  176.       INIT_I18N();
  177.       gimp_get_data (PLUG_IN_NAME, &pvals);
  178.       break;
  179.     }
  180.   
  181.   status = main_function (drawable, FALSE);
  182.  
  183.   if (run_mode != GIMP_RUN_NONINTERACTIVE)
  184.     gimp_displays_flush ();
  185.   if (run_mode == GIMP_RUN_INTERACTIVE && status == GIMP_PDB_SUCCESS)
  186.     gimp_set_data (PLUG_IN_NAME, &pvals, sizeof (ValueType));
  187.     g_free(preview_bits);
  188.  
  189.   values[0].type = GIMP_PDB_STATUS;
  190.   values[0].data.d_status = status;
  191. }
  192.  
  193. static GimpPDBStatusType
  194. main_function (GimpDrawable *drawable, 
  195.            gboolean      preview_mode)
  196. {
  197.   GimpPixelRgn  src_rgn, dest_rgn;
  198.   guchar    *src, *dest, *save_dest, *src_data, *dest_data;
  199.   gpointer   pr = NULL;
  200.   gint       x, y, x1, x2, y1, y2;
  201.   gint       gap, total, processed = 0;
  202.   gint       init_value, flag;
  203.   gint       bpp = 3;
  204.  
  205.   init_value = (pvals.max_p > 0) ? 0 : 255;
  206.   flag = (0 < pvals.max_p) ? 1 : -1;
  207.  
  208.   if (preview_mode) 
  209.     {
  210.       x1 = y1 = 0;
  211.       x2 = GTK_PREVIEW (preview)->buffer_width;
  212.       y2 = GTK_PREVIEW (preview)->buffer_height;
  213.       gap = 0; /* no alpha on preview */
  214.       bpp = GTK_PREVIEW (preview)->bpp;
  215.     } 
  216.   else 
  217.     {
  218.       gap = (gimp_drawable_has_alpha (drawable->id)) ? 1 : 0;
  219.       gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  220.       gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
  221.       gimp_pixel_rgn_init (&src_rgn, drawable,
  222.                x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
  223.       gimp_pixel_rgn_init (&dest_rgn, drawable,
  224.                x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
  225.       pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);
  226.       gimp_progress_init ( _("Max RGB: Scanning..."));
  227.     }
  228.   
  229.   total = (x2 - x1) * (y2 - y1);
  230.   if (total < 1)
  231.     return GIMP_PDB_EXECUTION_ERROR;
  232.  
  233.   if (preview_mode) 
  234.     { /* preview mode.  here we go again. see nova.c 
  235.      I just don't want to write a prev_pixel_rgn_process
  236.      and then find out someone else coded a much cooler
  237.      preview widget / functions for GIMP */
  238.       src_data = g_malloc (GTK_PREVIEW (preview)->rowstride * y2);
  239.       memcpy (src_data, preview_bits, GTK_PREVIEW (preview)->rowstride * y2);
  240.       dest_data = g_malloc (GTK_PREVIEW (preview)->rowstride * y2);
  241.       save_dest = dest_data;
  242.       
  243.       for (y = 0; y < y2; y++)
  244.     {
  245.       src  = src_data  + y * GTK_PREVIEW (preview)->rowstride;
  246.       dest = dest_data + y * GTK_PREVIEW (preview)->rowstride;
  247.       
  248.       for (x = 0; x < x2; x++)
  249.         {
  250.           gint   ch, max_ch = 0;
  251.           guchar max, tmp_value;
  252.           
  253.           max = init_value;
  254.           for (ch = 0; ch < 3; ch++)
  255.         if (flag * max <= flag * (tmp_value = (*src++)))
  256.           {
  257.             if (max == tmp_value)
  258.               {
  259.             max_ch += 1 << ch;
  260.               }
  261.             else
  262.               {
  263.             max_ch = 1 << ch; /* clear memories of old channels */
  264.             max = tmp_value;
  265.               }
  266.           }
  267.           
  268.           for ( ch = 0; ch < 3; ch++)
  269.         *dest++ = (guchar)(((max_ch & (1 << ch)) > 0) ? max : 0);
  270.           
  271.           if (gap) 
  272.         *dest++ = *src++;
  273.         }
  274.     }
  275.       
  276.       memcpy (GTK_PREVIEW (preview)->buffer, save_dest, GTK_PREVIEW (preview)->rowstride * y2);
  277.       gtk_widget_queue_draw (preview);
  278.     } 
  279.   else 
  280.     { /* normal mode */
  281.       for (; pr != NULL; pr = gimp_pixel_rgns_process (pr))
  282.     {
  283.       for (y = 0; y < src_rgn.h; y++)
  284.         {
  285.           src = src_rgn.data + y * src_rgn.rowstride;
  286.           dest = dest_rgn.data + y * dest_rgn.rowstride;
  287.           
  288.           for (x = 0; x < src_rgn.w; x++)
  289.         {
  290.           gint   ch, max_ch = 0;
  291.           guchar max, tmp_value;
  292.           
  293.           max = init_value;
  294.           for (ch = 0; ch < 3; ch++)
  295.             if (flag * max <= flag * (tmp_value = (*src++)))
  296.               {
  297.             if (max == tmp_value)
  298.               {
  299.                 max_ch += 1 << ch;
  300.               }
  301.             else
  302.               {
  303.                 max_ch = 1 << ch; /* clear memories of old channels */
  304.                 max = tmp_value;
  305.               }
  306.             
  307.               }
  308.           for ( ch = 0; ch < 3; ch++)
  309.             *dest++ = (guchar)(((max_ch & (1 << ch)) > 0) ? max : 0);
  310.           
  311.           if (gap) 
  312.             *dest++=*src++;
  313.           
  314.           if ((++processed % (total / PROGRESS_UPDATE_NUM + 1)) == 0)
  315.             gimp_progress_update ((gdouble) processed / (gdouble) total); 
  316.         }
  317.         }
  318.     }
  319.       gimp_progress_update (1.0);
  320.       gimp_drawable_flush (drawable);
  321.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  322.       gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
  323.       gimp_drawable_detach (drawable);
  324.     }
  325.   
  326.   return GIMP_PDB_SUCCESS;
  327. }
  328.  
  329.  
  330. /* dialog stuff */
  331. static gint
  332. dialog (GimpDrawable *drawable)
  333. {
  334.   GtkWidget *dlg;
  335.   GtkWidget *main_vbox;
  336.   GtkWidget *abox;
  337.   GtkWidget *frame;
  338.   GtkWidget *max;
  339.   GtkWidget *min;
  340.  
  341.   gimp_ui_init ("max_rgb", TRUE);
  342.  
  343.   dlg = gimp_dialog_new (_("Max RGB"), "max_rgb",
  344.              gimp_standard_help_func, "filters/max_rgb.html",
  345.              GTK_WIN_POS_MOUSE,
  346.              FALSE, TRUE, FALSE,
  347.  
  348.              _("OK"), ok_callback,
  349.              NULL, NULL, NULL, TRUE, FALSE,
  350.              _("Cancel"), gtk_widget_destroy,
  351.              NULL, 1, NULL, FALSE, TRUE,
  352.  
  353.              NULL);
  354.  
  355.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  356.               GTK_SIGNAL_FUNC (gtk_main_quit),
  357.               NULL);
  358.  
  359.   main_vbox = gtk_vbox_new (FALSE, 2);
  360.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 0);
  361.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_vbox, TRUE, TRUE, 0);
  362.   gtk_widget_show (main_vbox);
  363.  
  364.   frame = gtk_frame_new (_("Preview"));
  365.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  366.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  367.   gtk_widget_show (frame);
  368.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  369.   gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
  370.   gtk_container_add (GTK_CONTAINER (frame), abox);
  371.   gtk_widget_show (abox);
  372.   frame = gtk_frame_new (NULL);
  373.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  374.   gtk_container_add (GTK_CONTAINER (abox), frame);
  375.   gtk_widget_show (frame);
  376.   preview = preview_widget (drawable);
  377.   gtk_container_add (GTK_CONTAINER (frame), preview);
  378.   main_function (drawable, TRUE);
  379.   gtk_widget_show (preview);
  380.   
  381.   frame = gimp_radio_group_new2 (TRUE, _("Parameter Settings"),
  382.                  radio_callback,
  383.                  &pvals.max_p, (gpointer) pvals.max_p,
  384.  
  385.                  _("Hold the Maximal Channels"),
  386.                  (gpointer) MAX_CHANNELS, &max,
  387.                  _("Hold the Minimal Channels"),
  388.                  (gpointer) MIN_CHANNELS, &min,
  389.  
  390.                  NULL);
  391.   gtk_object_set_data (GTK_OBJECT (max), "drawable", drawable);
  392.   gtk_object_set_data (GTK_OBJECT (min), "drawable", drawable);
  393.  
  394.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  395.   gtk_container_add (GTK_CONTAINER (main_vbox), frame);
  396.   gtk_widget_show (frame);
  397.  
  398.   gtk_widget_show (dlg);
  399.  
  400.   gtk_main ();
  401.   gdk_flush ();
  402.  
  403.   return interface.run;
  404. }
  405.  
  406. static void
  407. radio_callback (GtkWidget *widget, 
  408.         gpointer  data)
  409. {
  410.   GimpDrawable *drawable;
  411.  
  412.   gimp_radio_button_update (widget, data);
  413.  
  414.   if (GTK_TOGGLE_BUTTON (widget)->active)
  415.     {
  416.       drawable = gtk_object_get_data (GTK_OBJECT (widget), "drawable");
  417.       main_function (drawable, TRUE);
  418.     }
  419. }
  420.  
  421. static void
  422. ok_callback (GtkWidget *widget,
  423.          gpointer   data)
  424. {
  425.   interface.run = TRUE;
  426.  
  427.   gtk_widget_destroy (GTK_WIDGET (data));
  428. }
  429.  
  430. static GtkWidget *
  431. preview_widget (GimpDrawable *drawable)
  432. {
  433.   gint       size;
  434.   GtkWidget *preview;
  435.  
  436.   preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  437.   fill_preview_with_thumb (preview, drawable->id);
  438.   size = GTK_PREVIEW (preview)->rowstride * GTK_PREVIEW (preview)->buffer_height;
  439.   preview_bits = g_malloc (size);
  440.   memcpy (preview_bits, GTK_PREVIEW (preview)->buffer, size);
  441.  
  442.   return preview;
  443. }
  444.  
  445. static void
  446. fill_preview_with_thumb (GtkWidget *widget, 
  447.              gint32     drawable_ID)
  448. {
  449.   guchar  *drawable_data;
  450.   gint     bpp;
  451.   gint     x,y;
  452.   gint     width  = PREVIEW_SIZE;
  453.   gint     height = PREVIEW_SIZE;
  454.   guchar  *src;
  455.   gdouble  r, g, b, a;
  456.   gdouble  c0, c1;
  457.   guchar  *p0, *p1;
  458.   guchar  *even, *odd;
  459.  
  460.   bpp = 0; /* Only returned */
  461.   
  462.   drawable_data = 
  463.     gimp_drawable_get_thumbnail_data (drawable_ID, &width, &height, &bpp);
  464.  
  465.   if (width < 1 || height < 1)
  466.     return;
  467.  
  468.   gtk_preview_size (GTK_PREVIEW (widget), width, height);
  469.  
  470.   even = g_malloc (width * 3);
  471.   odd  = g_malloc (width * 3);
  472.   src = drawable_data;
  473.  
  474.   for (y = 0; y < height; y++)
  475.     {
  476.       p0 = even;
  477.       p1 = odd;
  478.       
  479.       for (x = 0; x < width; x++) 
  480.     {
  481.       if(bpp == 4)
  482.         {
  483.           r =  ((gdouble)src[x*4+0])/255.0;
  484.           g = ((gdouble)src[x*4+1])/255.0;
  485.           b = ((gdouble)src[x*4+2])/255.0;
  486.           a = ((gdouble)src[x*4+3])/255.0;
  487.         }
  488.       else if(bpp == 3)
  489.         {
  490.           r =  ((gdouble)src[x*3+0])/255.0;
  491.           g = ((gdouble)src[x*3+1])/255.0;
  492.           b = ((gdouble)src[x*3+2])/255.0;
  493.           a = 1.0;
  494.         }
  495.       else
  496.         {
  497.           r = ((gdouble)src[x*bpp+0])/255.0;
  498.           g = b = r;
  499.           if(bpp == 2)
  500.         a = ((gdouble)src[x*bpp+1])/255.0;
  501.           else
  502.         a = 1.0;
  503.         }
  504.       
  505.       if ((x / GIMP_CHECK_SIZE_SM) & 1) 
  506.         {
  507.           c0 = GIMP_CHECK_LIGHT;
  508.           c1 = GIMP_CHECK_DARK;
  509.         } 
  510.       else 
  511.         {
  512.           c0 = GIMP_CHECK_DARK;
  513.           c1 = GIMP_CHECK_LIGHT;
  514.         }
  515.       
  516.     *p0++ = (c0 + (r - c0) * a) * 255.0;
  517.     *p0++ = (c0 + (g - c0) * a) * 255.0;
  518.     *p0++ = (c0 + (b - c0) * a) * 255.0;
  519.     
  520.     *p1++ = (c1 + (r - c1) * a) * 255.0;
  521.     *p1++ = (c1 + (g - c1) * a) * 255.0;
  522.     *p1++ = (c1 + (b - c1) * a) * 255.0;
  523.     
  524.       } /* for */
  525.       
  526.       if ((y / GIMP_CHECK_SIZE_SM) & 1)
  527.     gtk_preview_draw_row (GTK_PREVIEW (widget), (guchar *)odd,  0, y, width);
  528.       else
  529.     gtk_preview_draw_row (GTK_PREVIEW (widget), (guchar *)even, 0, y, width);
  530.  
  531.       src += width * bpp;
  532.     }
  533.  
  534.   g_free (even);
  535.   g_free (odd);
  536.   g_free (drawable_data);
  537. }
  538.