home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / scale_tool.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  15.0 KB  |  522 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. #include "config.h"
  20.  
  21. #include <glib.h>
  22.  
  23. #include "apptypes.h"
  24.  
  25. #include "appenv.h"
  26. #include "drawable.h"
  27. #include "gdisplay.h"
  28. #include "gimage_mask.h"
  29. #include "info_dialog.h"
  30. #include "scale_tool.h"
  31. #include "selection.h"
  32. #include "transform_tool.h"
  33. #include "undo.h"
  34.  
  35. #include "tile_manager_pvt.h"
  36.  
  37. #include "libgimp/gimpmath.h"
  38. #include "libgimp/gimplimits.h"
  39. #include "libgimp/gimpintl.h"
  40.  
  41.  
  42. /*  storage for information dialog fields  */
  43. static gchar      orig_width_buf[MAX_INFO_BUF];
  44. static gchar      orig_height_buf[MAX_INFO_BUF];
  45. static gdouble    size_vals[2];
  46. static gchar      x_ratio_buf[MAX_INFO_BUF];
  47. static gchar      y_ratio_buf[MAX_INFO_BUF];
  48.  
  49. /*  needed for original size unit update  */
  50. static GtkWidget *sizeentry;
  51.  
  52. /*  forward function declarations  */
  53. static void   scale_tool_recalc  (Tool *, void *);
  54. static void   scale_tool_motion  (Tool *, void *);
  55. static void   scale_info_update  (Tool *);
  56.  
  57. /*  callback functions for the info dialog fields  */
  58. static void   scale_size_changed (GtkWidget *widget, gpointer data);
  59. static void   scale_unit_changed (GtkWidget *widget, gpointer data);
  60.  
  61. TileManager *
  62. scale_tool_transform (Tool           *tool,
  63.               gpointer        gdisp_ptr,
  64.               TransformState  state)
  65. {
  66.   GDisplay      *gdisp;
  67.   TransformCore *transform_core;
  68.   GtkWidget     *spinbutton;
  69.  
  70.   gdisp = (GDisplay *) gdisp_ptr;
  71.   transform_core = (TransformCore *) tool->private;
  72.  
  73.   switch (state)
  74.     {
  75.     case INIT:
  76.       size_vals[0] = transform_core->x2 - transform_core->x1;
  77.       size_vals[1] = transform_core->y2 - transform_core->y1;
  78.  
  79.       if (!transform_info)
  80.     {
  81.       transform_info = info_dialog_new (_("Scaling Information"),
  82.                         gimp_standard_help_func,
  83.                         "tools/transform_scale.html");
  84.  
  85.       info_dialog_add_label (transform_info, _("Original Width:"),
  86.                  orig_width_buf);
  87.       info_dialog_add_label (transform_info, _("Height:"),
  88.                  orig_height_buf);
  89.  
  90.       spinbutton =
  91.         info_dialog_add_spinbutton (transform_info, _("Current Width:"),
  92.                     NULL, -1, 1, 1, 10, 1, 1, 2, NULL, NULL);
  93.       sizeentry =
  94.         info_dialog_add_sizeentry (transform_info, _("Height:"),
  95.                        size_vals, 1,
  96.                        gdisp->gimage->unit, "%a",
  97.                        TRUE, TRUE, FALSE,
  98.                        GIMP_SIZE_ENTRY_UPDATE_SIZE,
  99.                        scale_size_changed, tool);
  100.       gtk_signal_connect (GTK_OBJECT (sizeentry), "unit_changed",
  101.                   scale_unit_changed, tool);
  102.  
  103.       gimp_size_entry_add_field (GIMP_SIZE_ENTRY (sizeentry),
  104.                      GTK_SPIN_BUTTON (spinbutton), NULL);
  105.  
  106.       info_dialog_add_label (transform_info, _("Scale Ratio X:"),
  107.                  x_ratio_buf);
  108.       info_dialog_add_label (transform_info, _("Y:"),
  109.                  y_ratio_buf);
  110.  
  111.       gtk_table_set_row_spacing (GTK_TABLE (transform_info->info_table),
  112.                      1, 4);
  113.       gtk_table_set_row_spacing (GTK_TABLE (transform_info->info_table),
  114.                      2, 0);
  115.     }
  116.  
  117.       gtk_signal_handler_block_by_data (GTK_OBJECT (sizeentry), tool);
  118.  
  119.       gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (sizeentry),
  120.                 gdisp->gimage->unit);
  121.       if (gdisp->dot_for_dot)
  122.     gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (sizeentry), GIMP_UNIT_PIXEL);
  123.  
  124.       gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (sizeentry), 0,
  125.                       gdisp->gimage->xresolution, FALSE);
  126.       gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (sizeentry), 1,
  127.                       gdisp->gimage->yresolution, FALSE);
  128.  
  129.       gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), 0,
  130.                          GIMP_MIN_IMAGE_SIZE,
  131.                          GIMP_MAX_IMAGE_SIZE);
  132.       gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), 1,
  133.                          GIMP_MIN_IMAGE_SIZE,
  134.                          GIMP_MAX_IMAGE_SIZE);
  135.  
  136.       gimp_size_entry_set_size (GIMP_SIZE_ENTRY (sizeentry), 0,
  137.                 0, size_vals[0]);
  138.       gimp_size_entry_set_size (GIMP_SIZE_ENTRY (sizeentry), 1,
  139.                 0, size_vals[1]);
  140.  
  141.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (sizeentry), 0,
  142.                   size_vals[0]);
  143.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (sizeentry), 1,
  144.                   size_vals[1]);
  145.  
  146.       gtk_widget_set_sensitive (GTK_WIDGET (transform_info->shell), TRUE);
  147.  
  148.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (sizeentry), tool);
  149.  
  150.       transform_core->trans_info [X0] = (double) transform_core->x1;
  151.       transform_core->trans_info [Y0] = (double) transform_core->y1;
  152.       transform_core->trans_info [X1] = (double) transform_core->x2;
  153.       transform_core->trans_info [Y1] = (double) transform_core->y2;
  154.  
  155.       return NULL;
  156.       break;
  157.  
  158.     case MOTION:
  159.       scale_tool_motion (tool, gdisp_ptr);
  160.       scale_tool_recalc (tool, gdisp_ptr);
  161.       break;
  162.  
  163.     case RECALC:
  164.       scale_tool_recalc (tool, gdisp_ptr);
  165.       break;
  166.  
  167.     case FINISH:
  168.       gtk_widget_set_sensitive (GTK_WIDGET (transform_info->shell), FALSE);
  169.       return scale_tool_scale (gdisp->gimage,
  170.                    gimage_active_drawable (gdisp->gimage),
  171.                    gdisp,
  172.                    transform_core->trans_info,
  173.                    transform_core->original,
  174.                    transform_tool_smoothing (),
  175.                    transform_core->transform);
  176.       break;
  177.     }
  178.  
  179.   return NULL;
  180. }
  181.  
  182. Tool *
  183. tools_new_scale_tool (void)
  184. {
  185.   Tool          *tool;
  186.   TransformCore *private;
  187.  
  188.   tool = transform_core_new (SCALE, TRUE);
  189.  
  190.   private = tool->private;
  191.  
  192.   /*  set the scale specific transformation attributes  */
  193.   private->trans_func = scale_tool_transform;
  194.   private->trans_info[X0] = 0.0;
  195.   private->trans_info[Y0] = 0.0;
  196.   private->trans_info[X1] = 0.0;
  197.   private->trans_info[Y1] = 0.0;
  198.  
  199.   /*  assemble the transformation matrix  */
  200.   gimp_matrix3_identity (private->transform);
  201.  
  202.   return tool;
  203. }
  204.  
  205. void
  206. tools_free_scale_tool (Tool *tool)
  207. {
  208.   transform_core_free (tool);
  209. }
  210.  
  211. static void
  212. scale_info_update (Tool *tool)
  213. {
  214.   GDisplay      *gdisp;
  215.   TransformCore *transform_core;
  216.   gdouble        ratio_x, ratio_y;
  217.   gint           x1, y1, x2, y2, x3, y3, x4, y4;
  218.   GimpUnit       unit;
  219.   gdouble        unit_factor;
  220.   gchar          format_buf[16];
  221.  
  222.   static GimpUnit  label_unit = GIMP_UNIT_PIXEL;
  223.  
  224.   gdisp = (GDisplay *) tool->gdisp_ptr;
  225.   transform_core = (TransformCore *) tool->private;
  226.   unit = gimp_size_entry_get_unit (GIMP_SIZE_ENTRY (sizeentry));;
  227.  
  228.   /*  Find original sizes  */
  229.   x1 = transform_core->x1;
  230.   y1 = transform_core->y1;
  231.   x2 = transform_core->x2;
  232.   y2 = transform_core->y2;
  233.  
  234.   if (unit != GIMP_UNIT_PERCENT)
  235.     label_unit = unit;
  236.  
  237.   unit_factor = gimp_unit_get_factor (label_unit);
  238.  
  239.   if (label_unit) /* unit != GIMP_UNIT_PIXEL */
  240.     {
  241.       g_snprintf (format_buf, sizeof (format_buf), "%%.%df %s",
  242.           gimp_unit_get_digits (label_unit) + 1,
  243.           gimp_unit_get_symbol (label_unit));
  244.       g_snprintf (orig_width_buf, MAX_INFO_BUF, format_buf,
  245.           (x2 - x1) * unit_factor / gdisp->gimage->xresolution);
  246.       g_snprintf (orig_height_buf, MAX_INFO_BUF, format_buf,
  247.           (y2 - y1) * unit_factor / gdisp->gimage->yresolution);
  248.     }
  249.   else /* unit == GIMP_UNIT_PIXEL */
  250.     {
  251.       g_snprintf (orig_width_buf, MAX_INFO_BUF, "%d", x2 - x1);
  252.       g_snprintf (orig_height_buf, MAX_INFO_BUF, "%d", y2 - y1);
  253.     }
  254.  
  255.   /*  Find current sizes  */
  256.   x3 = (int) transform_core->trans_info [X0];
  257.   y3 = (int) transform_core->trans_info [Y0];
  258.   x4 = (int) transform_core->trans_info [X1];
  259.   y4 = (int) transform_core->trans_info [Y1];
  260.  
  261.   size_vals[0] = x4 - x3;
  262.   size_vals[1] = y4 - y3;
  263.  
  264.   ratio_x = ratio_y = 0.0;
  265.  
  266.   if (x2 - x1)
  267.     ratio_x = (double) (x4 - x3) / (double) (x2 - x1);
  268.   if (y2 - y1)
  269.     ratio_y = (double) (y4 - y3) / (double) (y2 - y1);
  270.  
  271.   g_snprintf (x_ratio_buf, MAX_INFO_BUF, "%0.2f", ratio_x);
  272.   g_snprintf (y_ratio_buf, MAX_INFO_BUF, "%0.2f", ratio_y);
  273.  
  274.   info_dialog_update (transform_info);
  275.   info_dialog_popup (transform_info);
  276. }
  277.  
  278. static void
  279. scale_size_changed (GtkWidget *widget,
  280.             gpointer   data)
  281. {
  282.   Tool          *tool;
  283.   TransformCore *transform_core;
  284.   GDisplay      *gdisp;
  285.   gint           width;
  286.   gint           height;
  287.  
  288.   tool = (Tool *)data;
  289.  
  290.   if (tool)
  291.     {
  292.       gdisp = (GDisplay *) tool->gdisp_ptr;
  293.       transform_core = (TransformCore *) tool->private;
  294.  
  295.       width = RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (widget), 0));
  296.       height = RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (widget), 1));
  297.  
  298.       if ((width != (transform_core->trans_info[X1] -
  299.              transform_core->trans_info[X0])) ||
  300.       (height != (transform_core->trans_info[Y1] -
  301.               transform_core->trans_info[Y0])))
  302.     {
  303.       draw_core_pause (transform_core->core, tool);
  304.       transform_core->trans_info[X1] =
  305.         transform_core->trans_info[X0] + width;
  306.       transform_core->trans_info[Y1] =
  307.         transform_core->trans_info[Y0] + height;
  308.       scale_tool_recalc (tool, gdisp);
  309.       draw_core_resume (transform_core->core, tool);
  310.     }
  311.     }
  312. }
  313.  
  314. static void
  315. scale_unit_changed (GtkWidget *widget,
  316.             gpointer   data)
  317. {
  318.   scale_info_update ((Tool *) data);
  319. }
  320.  
  321. static void
  322. scale_tool_motion (Tool *tool,
  323.            void *gdisp_ptr)
  324. {
  325.   GDisplay      *gdisp;
  326.   TransformCore *transform_core;
  327.   gdouble        ratio;
  328.   gdouble       *x1;
  329.   gdouble       *y1;
  330.   gdouble       *x2;
  331.   gdouble       *y2;
  332.   gint           w, h;
  333.   gint           dir_x, dir_y;
  334.   gint           diff_x, diff_y;
  335.  
  336.   gdisp = (GDisplay *) gdisp_ptr;
  337.   transform_core = (TransformCore *) tool->private;
  338.  
  339.   diff_x = transform_core->curx - transform_core->lastx;
  340.   diff_y = transform_core->cury - transform_core->lasty;
  341.  
  342.   switch (transform_core->function)
  343.     {
  344.     case HANDLE_1:
  345.       x1 = &transform_core->trans_info [X0];
  346.       y1 = &transform_core->trans_info [Y0];
  347.       x2 = &transform_core->trans_info [X1];
  348.       y2 = &transform_core->trans_info [Y1];
  349.       dir_x = dir_y = 1;
  350.       break;
  351.     case HANDLE_2:
  352.       x1 = &transform_core->trans_info [X1];
  353.       y1 = &transform_core->trans_info [Y0];
  354.       x2 = &transform_core->trans_info [X0];
  355.       y2 = &transform_core->trans_info [Y1];
  356.       dir_x = -1;
  357.       dir_y = 1;
  358.       break;
  359.     case HANDLE_3:
  360.       x1 = &transform_core->trans_info [X0];
  361.       y1 = &transform_core->trans_info [Y1];
  362.       x2 = &transform_core->trans_info [X1];
  363.       y2 = &transform_core->trans_info [Y0];
  364.       dir_x = 1;
  365.       dir_y = -1;
  366.       break;
  367.     case HANDLE_4:
  368.       x1 = &transform_core->trans_info [X1];
  369.       y1 = &transform_core->trans_info [Y1];
  370.       x2 = &transform_core->trans_info [X0];
  371.       y2 = &transform_core->trans_info [Y0];
  372.       dir_x = dir_y = -1;
  373.       break;
  374.     default :
  375.       return;
  376.     }
  377.  
  378.   /*  if just the mod1 key is down, affect only the height  */
  379.   if (transform_core->state & GDK_MOD1_MASK &&
  380.       ! (transform_core->state & GDK_CONTROL_MASK))
  381.     diff_x = 0;
  382.   /*  if just the control key is down, affect only the width  */
  383.   else if (transform_core->state & GDK_CONTROL_MASK &&
  384.        ! (transform_core->state & GDK_MOD1_MASK))
  385.     diff_y = 0;
  386.  
  387.   *x1 += diff_x;
  388.   *y1 += diff_y;
  389.  
  390.   if (dir_x > 0)
  391.     {
  392.       if (*x1 >= *x2) *x1 = *x2 - 1;
  393.     }
  394.   else
  395.     {
  396.       if (*x1 <= *x2) *x1 = *x2 + 1;
  397.     }
  398.  
  399.   if (dir_y > 0)
  400.     {
  401.       if (*y1 >= *y2) *y1 = *y2 - 1;
  402.     }
  403.   else
  404.     {
  405.       if (*y1 <= *y2) *y1 = *y2 + 1;
  406.     }
  407.  
  408.   /*  if both the control key & mod1 keys are down,
  409.    *  keep the aspect ratio intact 
  410.    */
  411.   if (transform_core->state & GDK_CONTROL_MASK &&
  412.       transform_core->state & GDK_MOD1_MASK)
  413.     {
  414.       ratio = (double) (transform_core->x2 - transform_core->x1) /
  415.         (double) (transform_core->y2 - transform_core->y1);
  416.  
  417.       w = ABS ((*x2 - *x1));
  418.       h = ABS ((*y2 - *y1));
  419.  
  420.       if (w > h * ratio)
  421.         h = w / ratio;
  422.       else
  423.         w = h * ratio;
  424.  
  425.       *y1 = *y2 - dir_y * h;
  426.       *x1 = *x2 - dir_x * w;
  427.     }
  428. }
  429.  
  430. static void
  431. scale_tool_recalc (Tool *tool,
  432.            void *gdisp_ptr)
  433. {
  434.   TransformCore *transform_core;
  435.   GDisplay      *gdisp;
  436.   gint           x1, y1, x2, y2;
  437.   gint           diffx, diffy;
  438.   gint           cx, cy;
  439.   gdouble        scalex, scaley;
  440.  
  441.   gdisp = (GDisplay *) tool->gdisp_ptr;
  442.   transform_core = (TransformCore *) tool->private;
  443.  
  444.   x1 = (int) transform_core->trans_info [X0];
  445.   y1 = (int) transform_core->trans_info [Y0];
  446.   x2 = (int) transform_core->trans_info [X1];
  447.   y2 = (int) transform_core->trans_info [Y1];
  448.  
  449.   scalex = scaley = 1.0;
  450.   if (transform_core->x2 - transform_core->x1)
  451.     scalex = (double) (x2 - x1) / (double) (transform_core->x2 - transform_core->x1);
  452.   if (transform_core->y2 - transform_core->y1)
  453.     scaley = (double) (y2 - y1) / (double) (transform_core->y2 - transform_core->y1);
  454.  
  455.   switch (transform_core->function)
  456.     {
  457.     case HANDLE_1:
  458.       cx = x2;  cy = y2;
  459.       diffx = x2 - transform_core->x2;
  460.       diffy = y2 - transform_core->y2;
  461.       break;
  462.     case HANDLE_2:
  463.       cx = x1;  cy = y2;
  464.       diffx = x1 - transform_core->x1;
  465.       diffy = y2 - transform_core->y2;
  466.       break;
  467.     case HANDLE_3:
  468.       cx = x2;  cy = y1;
  469.       diffx = x2 - transform_core->x2;
  470.       diffy = y1 - transform_core->y1;
  471.       break;
  472.     case HANDLE_4:
  473.       cx = x1;  cy = y1;
  474.       diffx = x1 - transform_core->x1;
  475.       diffy = y1 - transform_core->y1;
  476.       break;
  477.     default :
  478.       cx = x1; cy = y1;
  479.       diffx = diffy = 0;
  480.       break;
  481.     }
  482.  
  483.   /*  assemble the transformation matrix  */
  484.   gimp_matrix3_identity  (transform_core->transform);
  485.   gimp_matrix3_translate (transform_core->transform,
  486.               (double) -cx + diffx, (double) -cy + diffy);
  487.   gimp_matrix3_scale     (transform_core->transform, scalex, scaley);
  488.   gimp_matrix3_translate (transform_core->transform, (double) cx, (double) cy);
  489.  
  490.   /*  transform the bounding box  */
  491.   transform_core_transform_bounding_box (tool);
  492.  
  493.   /*  update the information dialog  */
  494.   scale_info_update (tool);
  495. }
  496.  
  497. TileManager *
  498. scale_tool_scale (GImage       *gimage,
  499.           GimpDrawable *drawable,
  500.           GDisplay     *gdisp,
  501.           gdouble      *trans_info,
  502.           TileManager  *float_tiles,
  503.           gboolean      interpolation,
  504.           GimpMatrix3   matrix)
  505. {
  506.   gimp_progress *progress;
  507.   TileManager   *ret;
  508.  
  509.   progress = progress_start (gdisp, _("Scaling..."), FALSE, NULL, NULL);
  510.  
  511.   ret = transform_core_do (gimage, drawable, float_tiles,
  512.                interpolation, matrix,
  513.                progress ? progress_update_and_flush :
  514.                (progress_func_t) NULL,
  515.                progress);
  516.  
  517.   if (progress)
  518.     progress_end (progress);
  519.  
  520.   return ret;
  521. }
  522.