home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / gimp / 2.0 / plug-ins / whirlpinch.py < prev    next >
Encoding:
Python Source  |  2006-07-10  |  9.2 KB  |  217 lines

  1. #!/usr/bin/env python
  2.  
  3. #   Gimp-Python - allows the writing of Gimp plugins in Python.
  4. #   Copyright (C) 1997  James Henstridge <james@daa.com.au>
  5. #
  6. #   This program is free software; you can redistribute it and/or modify
  7. #   it under the terms of the GNU General Public License as published by
  8. #   the Free Software Foundation; either version 2 of the License, or
  9. #   (at your option) any later version.
  10. #
  11. #   This program is distributed in the hope that it will be useful,
  12. #   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. #   GNU General Public License for more details.
  15. #
  16. #   You should have received a copy of the GNU General Public License
  17. #   along with this program; if not, write to the Free Software
  18. #   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  
  20. # Algorithms stolen from the whirl and pinch plugin distributed with Gimp,
  21. # by Federico Mena Quintero and Scott Goehring
  22. #
  23. # This version does the same thing, except there is no preview, and it is
  24. # written in python and is slower.
  25.  
  26. import math, struct
  27. from gimpfu import *
  28.  
  29. class pixel_fetcher:
  30.         def __init__(self, drawable):
  31.                 self.col = -1
  32.                 self.row = -1
  33.                 self.img_width = drawable.width
  34.                 self.img_height = drawable.height
  35.                 self.img_bpp = drawable.bpp
  36.                 self.img_has_alpha = drawable.has_alpha
  37.                 self.tile_width = 64
  38.                 self.tile_height = 64
  39.                 self.bg_colour = '\0\0\0\0'
  40.                 self.bounds = drawable.mask_bounds
  41.                 self.drawable = drawable
  42.                 self.tile = None
  43.         def set_bg_colour(self, r, g, b, a):
  44.                 self.bg_colour = struct.pack('BBB', r,g,b)
  45.                 if self.img_has_alpha:
  46.                         self.bg_colour = self.bg_colour + chr(a)
  47.         def get_pixel(self, x, y):
  48.                 sel_x1, sel_y1, sel_x2, sel_y2 = self.bounds
  49.                 if x < sel_x1 or x >= sel_x2 or y < sel_y1 or y >= sel_y2:
  50.                         return self.bg_colour
  51.                 col = x / self.tile_width
  52.                 coloff = x % self.tile_width
  53.                 row = y / self.tile_height
  54.                 rowoff = y % self.tile_height
  55.  
  56.                 if col != self.col or row != self.row or self.tile == None:
  57.                         self.tile = self.drawable.get_tile(FALSE, row, col)
  58.                         self.col = col
  59.                         self.row = row
  60.                 return self.tile[coloff, rowoff]
  61.  
  62. class Dummy:
  63.         pass
  64.  
  65. def python_whirl_pinch(image, drawable, whirl, pinch, radius):
  66.         self = Dummy()
  67.         self.width = drawable.width
  68.         self.height = drawable.height
  69.         self.bpp = drawable.bpp
  70.         self.has_alpha = drawable.has_alpha
  71.         self.bounds = drawable.mask_bounds
  72.         self.sel_x1, self.sel_y1, self.sel_x2, self.sel_y2 = \
  73.                      drawable.mask_bounds
  74.         self.sel_w = self.sel_x2 - self.sel_x1
  75.         self.sel_h = self.sel_y2 - self.sel_y1
  76.         self.cen_x = (self.sel_x1 + self.sel_x2 - 1) / 2.0
  77.         self.cen_y = (self.sel_y1 + self.sel_y2 - 1) / 2.0
  78.         xhsiz = (self.sel_w - 1) / 2.0
  79.         yhsiz = (self.sel_h - 1) / 2.0
  80.  
  81.         if xhsiz < yhsiz:
  82.                 self.scale_x = yhsiz / xhsiz
  83.                 self.scale_y = 1.0
  84.         elif xhsiz > yhsiz:
  85.                 self.scale_x = 1.0
  86.                 self.scale_y = xhsiz / yhsiz
  87.         else:
  88.                 self.scale_x = 1.0
  89.                 self.scale_y = 1.0
  90.  
  91.         self.radius = max(xhsiz, yhsiz);
  92.  
  93.         if not drawable.is_rgb and not drawable.is_grey:
  94.                 return
  95.  
  96.         gimp.tile_cache_ntiles(2 * (self.width + 63) / 64)
  97.  
  98.         whirl = whirl * math.pi / 180
  99.         dest_rgn = drawable.get_pixel_rgn(self.sel_x1, self.sel_y1,
  100.                                           self.sel_w, self.sel_h, TRUE, TRUE)
  101.         pft = pixel_fetcher(drawable)
  102.         pfb = pixel_fetcher(drawable)
  103.         bg_colour = gimp.get_background()
  104.         pft.set_bg_colour(bg_colour[0], bg_colour[1], bg_colour[2], 0)
  105.         pfb.set_bg_colour(bg_colour[0], bg_colour[1], bg_colour[2], 0)
  106.         progress = 0
  107.         max_progress = self.sel_w * self.sel_h
  108.         gimp.progress_init("Whirling and pinching...")
  109.         self.radius2 = self.radius * self.radius * radius
  110.         pixel = ['', '', '', '']
  111.         values = [0,0,0,0]
  112.         for row in range(self.sel_y1, (self.sel_y1+self.sel_y2)/2+1):
  113.                 top_p = ''
  114.                 bot_p = ''
  115.                 for col in range(self.sel_x1, self.sel_x2):
  116.                         q, cx, cy = calc_undistorted_coords(self, col,
  117.                                                 row, whirl, pinch, radius)
  118.                         if q:
  119.                                 if cx >= 0: ix = int(cx)
  120.                                 else:       ix = -(int(-cx) + 1)
  121.                                 if cy >= 0: iy = int(cy)
  122.                                 else:       iy = -(int(-cx) + 1)
  123.                                 pixel[0] = pft.get_pixel(ix, iy)
  124.                                 pixel[1] = pft.get_pixel(ix+1, iy)
  125.                                 pixel[2] = pft.get_pixel(ix, iy+1)
  126.                                 pixel[3] = pft.get_pixel(ix+1, iy+1)
  127.                                 for i in range(self.bpp):
  128.                                         values[0] = ord(pixel[0][i])
  129.                                         values[1] = ord(pixel[1][i])
  130.                                         values[2] = ord(pixel[2][i])
  131.                                         values[3] = ord(pixel[3][i])
  132.                                         top_p = top_p + bilinear(cx,cy, values)
  133.                                 cx = self.cen_x + (self.cen_x - cx)
  134.                                 cy = self.cen_y + (self.cen_y - cy)
  135.                                 if cx >= 0: ix = int(cx)
  136.                                 else:       ix = -(int(-cx) + 1)
  137.                                 if cy >= 0: iy = int(cy)
  138.                                 else:       iy = -(int(-cy) + 1)
  139.                                 pixel[0] = pfb.get_pixel(ix, iy)
  140.                                 pixel[1] = pfb.get_pixel(ix+1, iy)
  141.                                 pixel[2] = pfb.get_pixel(ix, iy+1)
  142.                                 pixel[3] = pfb.get_pixel(ix+1, iy+1)
  143.                                 tmp = ''
  144.                                 for i in range(self.bpp):
  145.                                         values[0] = ord(pixel[0][i])
  146.                                         values[1] = ord(pixel[1][i])
  147.                                         values[2] = ord(pixel[2][i])
  148.                                         values[3] = ord(pixel[3][i])
  149.                                         tmp = tmp + bilinear(cx,cy, values)
  150.                                 bot_p = tmp + bot_p
  151.                         else:
  152.                                 top_p = top_p + pft.get_pixel(col, row)
  153.                                 bot_p = pfb.get_pixel((self.sel_x2 - 1) -
  154.                                         (col - self.sel_x1), (self.sel_y2-1) -
  155.                                         (row - self.sel_y1)) + bot_p
  156.                 dest_rgn[self.sel_x1:self.sel_x2, row] = top_p
  157.                 dest_rgn[self.sel_x1:self.sel_x2, (self.sel_y2 - 1)
  158.                          - (row - self.sel_y1)] = bot_p
  159.                 progress = progress + self.sel_w * 2
  160.                 gimp.progress_update(float(progress) / max_progress)
  161.         drawable.flush()
  162.         drawable.merge_shadow(TRUE)
  163.         drawable.update(self.sel_x1,self.sel_y1,self.sel_w,self.sel_h)
  164.  
  165. def calc_undistorted_coords(self, wx, wy, whirl, pinch, radius):
  166.         dx = (wx - self.cen_x) * self.scale_x
  167.         dy = (wy - self.cen_y) * self.scale_y
  168.         d = dx * dx + dy * dy
  169.         inside = d < self.radius2
  170.  
  171.         if inside:
  172.                 dist = math.sqrt(d / radius) / self.radius
  173.                 if (d == 0.0):
  174.                         factor = 1.0
  175.                 else:
  176.                         factor = math.pow(math.sin(math.pi / 2 * dist),
  177.                                           -pinch)
  178.                 dx = dx * factor
  179.                 dy = dy * factor
  180.                 factor = 1 - dist
  181.                 ang = whirl * factor * factor
  182.                 sina = math.sin(ang)
  183.                 cosa = math.cos(ang)
  184.                 x = (cosa * dx - sina * dy) / self.scale_x + self.cen_x
  185.                 y = (sina * dx + cosa * dy) / self.scale_y + self.cen_y
  186.         else:
  187.                 x = wx
  188.                 y = wy
  189.         return inside, float(x), float(y)
  190.         
  191. def bilinear(x, y, values):
  192.         x = x % 1.0
  193.         y = y % 1.0
  194.         m0 = values[0] + x * (values[1] - values[0])
  195.         m1 = values[2] + x * (values[3] - values[2])
  196.         return chr(int(m0 + y * (m1 - m0)))
  197.  
  198.  
  199. register(
  200.         "python_fu_whirl_pinch",
  201.         "Distorts an image by whirling and pinching",
  202.         "Distorts an image by whirling and pinching",
  203.         "James Henstridge (translated from C plugin)",
  204.         "James Henstridge",
  205.         "1997-1999",
  206.         "<Image>/Python-Fu/Distorts/_Whirl and Pinch",
  207.         "RGB*, GRAY*",
  208.         [
  209.                 (PF_SLIDER, "whirl", "Whirl angle", 90, (-360, 360, 1)),
  210.                 (PF_FLOAT, "pinch", "Pinch amount", 0),
  211.                 (PF_FLOAT, "radius", "radius", 1)
  212.         ],
  213.         [],
  214.         python_whirl_pinch)
  215.  
  216. main()
  217.