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 / tile.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-10  |  12.6 KB  |  476 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. /*
  20.  * This filter tiles an image to arbitrary width and height
  21.  */
  22. #include "config.h"
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27.  
  28. #include <gtk/gtk.h>
  29.  
  30. #include <libgimp/gimp.h>
  31. #include <libgimp/gimpui.h>
  32.  
  33. #include "libgimp/stdplugins-intl.h"
  34.  
  35.  
  36. typedef struct
  37. {
  38.   gint new_width;
  39.   gint new_height;
  40.   gint constrain;
  41.   gint new_image;
  42. } TileVals;
  43.  
  44. typedef struct
  45. {
  46.   GtkWidget *sizeentry;
  47.   GtkWidget *chainbutton;
  48.   gint       run;
  49. } TileInterface;
  50.  
  51.  
  52. /* Declare local functions.
  53.  */
  54. static void    query  (void);
  55. static void    run    (gchar      *name,
  56.                gint        nparams,
  57.                GimpParam  *param,
  58.                gint       *nreturn_vals,
  59.                GimpParam **return_vals);
  60.  
  61. static gint32  tile             (gint32     image_id,
  62.                  gint32     drawable_id,
  63.                  gint32    *layer_id);
  64.  
  65. static gint    tile_dialog      (gint32     image_ID,
  66.                  gint32     drawable_ID);
  67. static void    tile_ok_callback (GtkWidget *widget,
  68.                  gpointer   data);
  69.  
  70.  
  71. GimpPlugInInfo PLUG_IN_INFO =
  72. {
  73.   NULL,  /* init_proc  */
  74.   NULL,  /* quit_proc  */
  75.   query, /* query_proc */
  76.   run,   /* run_proc   */
  77. };
  78.  
  79. static TileVals tvals =
  80. {
  81.   1,     /* new_width  */
  82.   1,     /* new_height */
  83.   TRUE,  /* constrain  */
  84.   TRUE   /* new_image  */
  85. };
  86.  
  87. static TileInterface tint =
  88. {
  89.   NULL,  /* sizeentry */
  90.   FALSE  /* run       */
  91. };
  92.  
  93.  
  94. MAIN ()
  95.  
  96. static void
  97. query (void)
  98. {
  99.   static GimpParamDef args[] =
  100.   {
  101.     { GIMP_PDB_INT32,    "run_mode",  "Interactive, non-interactive" },
  102.     { GIMP_PDB_IMAGE,    "image",      "Input image (unused)"        },
  103.     { GIMP_PDB_DRAWABLE, "drawable",   "Input drawable"              },
  104.     { GIMP_PDB_INT32,    "new_width",  "New (tiled) image width"     },
  105.     { GIMP_PDB_INT32,    "new_height", "New (tiled) image height"    },
  106.     { GIMP_PDB_INT32,    "new_image",  "Create a new image?"         }
  107.   };
  108.   static gint nargs = sizeof (args) / sizeof (args[0]);
  109.  
  110.   static GimpParamDef return_vals[] =
  111.   {
  112.     { GIMP_PDB_IMAGE, "new_image", "Output image (N/A if new_image == FALSE)" },
  113.     { GIMP_PDB_LAYER, "new_layer", "Output layer (N/A if new_image == FALSE)" }
  114.   };
  115.   static gint nreturn_vals = sizeof (return_vals) / sizeof (return_vals[0]);
  116.  
  117.   gimp_install_procedure ("plug_in_tile",
  118.               "Create a new image which is a tiled version of the "
  119.               "input drawable",
  120.               "This function creates a new image with a single "
  121.               "layer sized to the specified 'new_width' and "
  122.               "'new_height' parameters.  The specified drawable "
  123.               "is tiled into this layer.  The new layer will have "
  124.               "the same type as the specified drawable and the "
  125.               "new image will have a corresponding base type.",
  126.               "Spencer Kimball & Peter Mattis",
  127.               "Spencer Kimball & Peter Mattis",
  128.               "1996-1997",
  129.               N_("<Image>/Filters/Map/Tile..."),
  130.               "RGB*, GRAY*, INDEXED*",
  131.               GIMP_PLUGIN,
  132.               nargs, nreturn_vals,
  133.               args, return_vals);
  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.   static GimpParam  values[3];
  144.   GimpRunModeType   run_mode;
  145.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  146.   gint32  new_layer;
  147.   gint    width;
  148.   gint    height;
  149.  
  150.   run_mode = param[0].data.d_int32;
  151.  
  152.   *nreturn_vals = 3;
  153.   *return_vals  = values;
  154.  
  155.   values[0].type          = GIMP_PDB_STATUS;
  156.   values[0].data.d_status = status;
  157.   values[1].type          = GIMP_PDB_IMAGE;
  158.   values[2].type          = GIMP_PDB_LAYER;
  159.  
  160.   width  = gimp_drawable_width  (param[2].data.d_drawable);
  161.   height = gimp_drawable_height (param[2].data.d_drawable);
  162.  
  163.   switch (run_mode)
  164.     {
  165.     case GIMP_RUN_INTERACTIVE:
  166.       INIT_I18N_UI();
  167.       /*  Possibly retrieve data  */
  168.       gimp_get_data ("plug_in_tile", &tvals);
  169.  
  170.       /*  First acquire information with a dialog  */
  171.       if (! tile_dialog (param[1].data.d_image,
  172.              param[2].data.d_drawable))
  173.     return;
  174.       break;
  175.  
  176.     case GIMP_RUN_NONINTERACTIVE:
  177.       INIT_I18N();
  178.       /*  Make sure all the arguments are there!  */
  179.       if (nparams != 6)
  180.     {
  181.       status = GIMP_PDB_CALLING_ERROR;
  182.     }
  183.       else
  184.     {
  185.       tvals.new_width  = param[3].data.d_int32;
  186.       tvals.new_height = param[4].data.d_int32;
  187.       tvals.new_image  = param[5].data.d_int32 ? TRUE : FALSE;
  188.  
  189.       if (tvals.new_width < 0 || tvals.new_height < 0)
  190.         status = GIMP_PDB_CALLING_ERROR;
  191.     }
  192.       break;
  193.  
  194.     case GIMP_RUN_WITH_LAST_VALS:
  195.       INIT_I18N();
  196.       /*  Possibly retrieve data  */
  197.       gimp_get_data ("plug_in_tile", &tvals);
  198.       break;
  199.  
  200.     default:
  201.       break;
  202.     }
  203.  
  204.   /*  Make sure that the drawable is gray or RGB color  */
  205.   if (status == GIMP_PDB_SUCCESS)
  206.     {
  207.       gimp_progress_init (_("Tiling..."));
  208.       gimp_tile_cache_ntiles (2 * (width + 1) / gimp_tile_width ());
  209.  
  210.       values[1].data.d_image = tile (param[1].data.d_image,
  211.                      param[2].data.d_drawable,
  212.                      &new_layer);
  213.       values[2].data.d_layer = new_layer;
  214.  
  215.       /*  Store data  */
  216.       if (run_mode == GIMP_RUN_INTERACTIVE)
  217.     gimp_set_data ("plug_in_tile", &tvals, sizeof (TileVals));
  218.  
  219.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  220.     {
  221.       if (tvals.new_image)
  222.         gimp_display_new (values[1].data.d_image);
  223.       else
  224.         gimp_displays_flush ();
  225.     }
  226.     }
  227.  
  228.   values[0].data.d_status = status;
  229. }
  230.  
  231. static gint32
  232. tile (gint32  image_id,
  233.       gint32  drawable_id,
  234.       gint32 *layer_id)
  235. {
  236.   GimpPixelRgn       src_rgn;
  237.   GimpPixelRgn       dest_rgn;
  238.   GimpDrawable      *drawable;
  239.   GimpDrawable      *new_layer;
  240.   GimpImageBaseType  image_type;
  241.   gint32   new_image_id;
  242.   gint     old_width, old_height;
  243.   gint     width, height;
  244.   gint     i, j, k;
  245.   gint     progress, max_progress;
  246.   gpointer pr;
  247.  
  248.   /* sanity check parameters */
  249.   if (tvals.new_width < 1 || tvals.new_height < 1)
  250.     {
  251.       *layer_id = -1;
  252.       return -1;
  253.     }
  254.  
  255.   /* initialize */
  256.   image_type = GIMP_RGB;
  257.   new_image_id = 0;
  258.  
  259.   old_width  = gimp_drawable_width  (drawable_id);
  260.   old_height = gimp_drawable_height (drawable_id);
  261.  
  262.   if (tvals.new_image)
  263.     {
  264.       /*  create  a new image  */
  265.       switch (gimp_drawable_type (drawable_id))
  266.     {
  267.     case GIMP_RGB_IMAGE : case GIMP_RGBA_IMAGE:
  268.       image_type = GIMP_RGB;
  269.       break;
  270.     case GIMP_GRAY_IMAGE : case GIMP_GRAYA_IMAGE:
  271.       image_type = GIMP_GRAY;
  272.       break;
  273.     case GIMP_INDEXED_IMAGE : case GIMP_INDEXEDA_IMAGE:
  274.       image_type = GIMP_INDEXED;
  275.       break;
  276.     }
  277.  
  278.       new_image_id = gimp_image_new (tvals.new_width, tvals.new_height,
  279.                      image_type);
  280.       *layer_id = gimp_layer_new (new_image_id, _("Background"),
  281.                   tvals.new_width, tvals.new_height,
  282.                   gimp_drawable_type (drawable_id),
  283.                   100, GIMP_NORMAL_MODE);
  284.  
  285.       if (*layer_id == -1)
  286.     return -1;
  287.       
  288.       gimp_image_add_layer (new_image_id, *layer_id, 0);
  289.       new_layer = gimp_drawable_get (*layer_id);
  290.  
  291.       /*  Get the specified drawable  */
  292.       drawable = gimp_drawable_get (drawable_id);
  293.     }
  294.   else
  295.     {
  296.       gimp_undo_push_group_start (image_id);
  297.  
  298.       gimp_image_resize (image_id, 
  299.              tvals.new_width, tvals.new_height, 
  300.              0, 0);
  301.  
  302.       if (gimp_drawable_is_layer (drawable_id))
  303.     gimp_layer_resize (drawable_id, 
  304.                tvals.new_width, tvals.new_height, 
  305.                0, 0);
  306.  
  307.       /*  Get the specified drawable  */
  308.       drawable = gimp_drawable_get (drawable_id);
  309.       new_layer = drawable;
  310.     }
  311.  
  312.   /*  progress  */
  313.   progress = 0;
  314.   max_progress = tvals.new_width * tvals.new_height;
  315.  
  316.   /*  tile...  */
  317.   for (i = 0; i < tvals.new_height; i += old_height)
  318.     {
  319.       height = old_height;
  320.       if (height + i > tvals.new_height)
  321.     height = tvals.new_height - i;
  322.  
  323.       for (j = 0; j < tvals.new_width; j += old_width)
  324.     {
  325.       width = old_width;
  326.  
  327.       if (width + j > tvals.new_width)
  328.         width = tvals.new_width - j;
  329.  
  330.       gimp_pixel_rgn_init (&src_rgn, drawable,
  331.                    0, 0, width, height, FALSE, FALSE);
  332.       gimp_pixel_rgn_init (&dest_rgn, new_layer,
  333.                    j, i, width, height, TRUE, FALSE);
  334.  
  335.       for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);
  336.            pr != NULL;
  337.            pr = gimp_pixel_rgns_process (pr))
  338.         {
  339.           for (k = 0; k < src_rgn.h; k++)
  340.         memcpy (dest_rgn.data + k * dest_rgn.rowstride,
  341.             src_rgn.data + k * src_rgn.rowstride,
  342.             src_rgn.w * src_rgn.bpp);
  343.  
  344.           progress += src_rgn.w * src_rgn.h;
  345.           gimp_progress_update ((gdouble) progress / 
  346.                     (gdouble) max_progress);
  347.         }
  348.     }
  349.     }
  350.  
  351.   /*  copy the colormap, if necessary  */
  352.   if (image_type == GIMP_INDEXED && tvals.new_image)
  353.     {
  354.       gint    ncols;
  355.       guchar *cmap;
  356.  
  357.       cmap = gimp_image_get_cmap (image_id, &ncols);
  358.       gimp_image_set_cmap (new_image_id, cmap, ncols);
  359.       g_free (cmap);
  360.     }
  361.  
  362.   if (tvals.new_image)
  363.     {
  364.       gimp_drawable_flush (new_layer);
  365.       gimp_drawable_detach (new_layer);
  366.     }
  367.   else
  368.     gimp_undo_push_group_end (image_id);
  369.  
  370.   gimp_drawable_flush (drawable);
  371.   gimp_drawable_detach (drawable);
  372.  
  373.   return new_image_id;
  374. }
  375.  
  376. static gint
  377. tile_dialog (gint32 image_ID,
  378.          gint32 drawable_ID)
  379. {
  380.   GtkWidget *dlg;
  381.   GtkWidget *frame;
  382.   GtkWidget *sizeentry;
  383.   GtkWidget *toggle;
  384.   gint       width;
  385.   gint       height;
  386.   gdouble    xres;
  387.   gdouble    yres;
  388.   GimpUnit   unit;
  389.  
  390.   gimp_ui_init ("tile", FALSE);
  391.  
  392.   width  = gimp_drawable_width (drawable_ID);
  393.   height = gimp_drawable_height (drawable_ID);
  394.   unit   = gimp_image_get_unit (image_ID);
  395.   gimp_image_get_resolution (image_ID, &xres, &yres);
  396.  
  397.   tvals.new_width  = width;
  398.   tvals.new_height = height;
  399.  
  400.   dlg = gimp_dialog_new (_("Tile"), "tile",
  401.              gimp_standard_help_func, "filters/tile.html",
  402.              GTK_WIN_POS_MOUSE,
  403.              FALSE, TRUE, FALSE,
  404.  
  405.              _("OK"), tile_ok_callback,
  406.              NULL, NULL, NULL, TRUE, FALSE,
  407.              _("Cancel"), gtk_widget_destroy,
  408.              NULL, 1, NULL, FALSE, TRUE,
  409.  
  410.              NULL);
  411.  
  412.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  413.               GTK_SIGNAL_FUNC (gtk_main_quit),
  414.               NULL);
  415.  
  416.   /*  parameter settings  */
  417.   frame = gtk_frame_new (_("Tile to New Size"));
  418.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  419.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  420.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0);
  421.   gtk_widget_show (frame);
  422.  
  423.   sizeentry = gimp_coordinates_new (unit, "%a", TRUE, TRUE, 75,
  424.                     GIMP_SIZE_ENTRY_UPDATE_SIZE,
  425.  
  426.                     tvals.constrain, TRUE,
  427.  
  428.                     _("Width:"), width, xres,
  429.                     1, GIMP_MAX_IMAGE_SIZE,
  430.                     0, width,
  431.  
  432.                     _("Height:"), height, yres,
  433.                     1, GIMP_MAX_IMAGE_SIZE,
  434.                     0, height);
  435.   gtk_container_set_border_width (GTK_CONTAINER (sizeentry), 4);
  436.   gtk_container_add (GTK_CONTAINER (frame), sizeentry);
  437.   gtk_table_set_row_spacing (GTK_TABLE (sizeentry), 1, 4);
  438.   gtk_widget_show (sizeentry);
  439.  
  440.   tint.sizeentry = sizeentry;
  441.   tint.chainbutton = GTK_WIDGET (GIMP_COORDINATES_CHAINBUTTON (sizeentry));
  442.  
  443.   toggle = gtk_check_button_new_with_label (_("Create New Image"));
  444.   gtk_table_attach (GTK_TABLE (sizeentry), toggle, 0, 4, 2, 3,
  445.             GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
  446.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  447.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  448.               &tvals.new_image);
  449.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), tvals.new_image);
  450.   gtk_widget_show (toggle);
  451.  
  452.   gtk_widget_show (dlg);
  453.  
  454.   gtk_main ();
  455.   gdk_flush ();
  456.  
  457.   return tint.run;
  458. }
  459.  
  460. static void
  461. tile_ok_callback (GtkWidget *widget,
  462.           gpointer   data)
  463. {
  464.   tvals.new_width =
  465.     RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (tint.sizeentry), 0));
  466.   tvals.new_height =
  467.     RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (tint.sizeentry), 1));
  468.  
  469.   tvals.constrain =
  470.     gimp_chain_button_get_active (GIMP_CHAIN_BUTTON (tint.chainbutton));
  471.  
  472.   tint.run = TRUE;
  473.  
  474.   gtk_widget_destroy (GTK_WIDGET (data));
  475. }
  476.