diff --git a/plug-ins/pygimp/plug-ins/palette-sort.py b/plug-ins/pygimp/plug-ins/palette-sort.py
index 1d590d1..f3a48a9 100644
--- a/plug-ins/pygimp/plug-ins/palette-sort.py
+++ b/plug-ins/pygimp/plug-ins/palette-sort.py
@@ -14,31 +14,127 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 from gimpfu import *
+from colorsys import rgb_to_yiq
 
 gettext.install("gimp20-python", gimp.locale_directory, unicode=True)
 
-def palette_sort (palette, model, channel, ascending):
+AVAILABLE_CHANNELS = (_("Red"), _("Green"), _("Blue"),
+                      _("Luma (Y)"),
+                      _("Hue"), _("Saturation"), _("Value"),
+                      _("Saturation (HSL)"), _("Lightness (HSL)"))
+GRAIN_UNIT = 256
+GRAIN_SIZE = (1.0, 1.0 , 1.0,
+              1.0,
+              360., 100., 100.,
+              100., 100.,
+              100., 256., 256.,
+              256., 360.)
+GRAIN_SIZE = tuple([v / GRAIN_UNIT for v in GRAIN_SIZE])
+SELECT_ALL = 0
+SELECT_ARRAY = 1
+SELECT_SLICE = 2
+SELECT_PARTITIONED = 3
+SELECTIONS = (SELECT_ALL, SELECT_ARRAY, SELECT_SLICE, SELECT_PARTITIONED)
+
+def noop(v):
+    return v
+def to_hsv(v):
+    return v.to_hsv()
+def to_hsl(v):
+    return v.to_hsl()
+def to_yiq(v):
+    return rgb_to_yiq(*v[:-1])
+channel_getters = [ (noop, 0), (noop, 1), (noop, 2),
+                    (to_yiq, 0),
+                    (to_hsv, 0), (to_hsv, 1), (to_hsv, 2),
+                    (to_hsl, 1), (to_hsl, 2)]
+
+
+try:
+    from colormath.color_objects import RGBColor, LabColor, LCHabColor
+    AVAILABLE_CHANNELS = AVAILABLE_CHANNELS + (_("Lightness (LAB)"), _("A-color"), _("B-color"),
+                                               _("Chroma (LCHab)"), _("Hue (LCHab)"))
+    to_lab = lambda v: RGBColor(*v[:-1]).convert_to('LAB').get_value_tuple()
+    to_lchab = lambda v: RGBColor(*v[:-1]).convert_to('LCHab').get_value_tuple()
+    channel_getters.extend([(to_lab, 0), (to_lab, 1), (to_lab, 2),
+                            (to_lchab, 1), (to_lchab, 2)])
+except ImportError:
+    pass
+
+def palette_sort (palette, channel, ascending, granularity, selection,
+                  start, length, nrows, partitionchannel, pgranularity):
+
+    granularity = max(1.0, granularity)
+    pgranularity = max(1.0, pgranularity)
+    if granularity > 1.0:
+        grain = max(0.00001, GRAIN_SIZE[channel] * granularity)
+    else:
+        grain = 0.00001
+    if pgranularity > 1.0:
+        pgrain = max(0.00001, GRAIN_SIZE[partitionchannel] * pgranularity)
+    else:
+        pgrain = 0.00001
     #If palette is read only, work on a copy:
     editable = pdb.gimp_palette_is_editable(palette)
-    if not editable:palette = pdb.gimp_palette_duplicate (palette)
+    if not editable:
+        palette = pdb.gimp_palette_duplicate (palette)
 
     num_colors = pdb.gimp_palette_get_info (palette)
-    entry_list = []
-    for i in xrange (num_colors):
-        entry =  (pdb.gimp_palette_entry_get_name (palette, i),
-                  pdb.gimp_palette_entry_get_color (palette, i))
-        index = entry[1][channel]
-        if model == "HSV":
-            index = entry[1].to_hsv()[channel]
-        else:
-            index = entry[1][channel]
-        entry_list.append ((index, entry))
-    entry_list.sort(lambda x,y: cmp(x[0], y[0]))
-    if not ascending:
-        entry_list.reverse()
-    for i in xrange(num_colors):
-        pdb.gimp_palette_entry_set_name (palette, i, entry_list[i][1][0])
-        pdb.gimp_palette_entry_set_color (palette, i, entry_list[i][1][1])
+    if length == -1:
+        length = num_colors - start
+    length = max(1, length)
+    channels_getter, channel_index = channel_getters[channel]
+
+    def get_colors (start, end):
+        result = []
+        for i in range (start, end):
+            entry =  (pdb.gimp_palette_entry_get_name (palette, i),
+                      pdb.gimp_palette_entry_get_color (palette, i))
+            index = channels_getter(entry[1])[channel_index]
+            index = (index - (index % grain))
+            result.append((index, entry))
+        return result
+
+    if selection == SELECT_ALL:
+        entry_list = get_colors(0, num_colors)
+        entry_list.sort(key=lambda v:v[0], reverse=not ascending)
+        for i in range(num_colors):
+            pdb.gimp_palette_entry_set_name (palette, i, entry_list[i][1][0])
+            pdb.gimp_palette_entry_set_color (palette, i, entry_list[i][1][1])
+
+    elif selection == SELECT_PARTITIONED:
+        partition_spans = [1]
+        pchannels_getter, pchannel_index = channel_getters[partitionchannel]
+        old_color = pdb.gimp_palette_entry_get_color (palette, 0)
+        old_partition = pchannels_getter(old_color)[pchannel_index]
+        old_partition = old_partition - (old_partition % pgrain)
+        for i in range(start + 1, start + length):
+            this_color = pdb.gimp_palette_entry_get_color (palette, i)
+            this_partition = pchannels_getter(this_color)[pchannel_index]
+            this_partition = this_partition - (this_partition % pgrain)
+            if this_partition == old_partition:
+                partition_spans[-1] += 1
+            else:
+                partition_spans.append(1)
+                old_partition = this_partition
+        base = start
+        for size in partition_spans:
+            palette_sort(palette, channel, ascending, granularity, SELECT_SLICE, base, size, 0, 0, 1.0)
+            base += size
+    else:
+        if selection != SELECT_ARRAY:
+            nrows = 1
+        stride = length
+        if num_colors < (start + stride * nrows) - 1:
+            raise ValueError('Not enough entries in palette to sort complete rows!'
+                             'got %d, expected %d' % (num_colors, start + stride * nrows))
+
+        for row_start in range(start, start + stride * nrows, stride):
+            sublist = get_colors(row_start, row_start + stride)
+            sublist.sort(key=lambda v:v[0], reverse=not ascending)
+            for i, entry in zip(range(row_start, row_start + stride), sublist):
+                pdb.gimp_palette_entry_set_name (palette, i, entry[1][0])
+                pdb.gimp_palette_entry_set_color (palette, i, entry[1][1])
 
     return palette
 
@@ -47,21 +143,25 @@ register(
     "python-fu-palette-sort",
     N_("Sort the colors in a palette"),
     "palette_merge (palette, model, channel, ascending) -> new_palette",
-    "Joao S. O. Bueno Calligaris, Carol Spears",
+    "Joao S. O. Bueno Calligaris, Carol Spears, David Gowers",
     "Joao S. O. Bueno Calligaris",
     "2006",
     N_("_Sort Palette..."),
     "",
     [
         (PF_PALETTE, "palette",  _("Palette"), ""),
-        (PF_RADIO,   "model",    _("Color _model"), "HSV",
-                                    ((_("RGB"), "RGB"),
-                                     (_("HSV"), "HSV"))),
-        (PF_RADIO,   "channel",  _("Channel to _sort"), 2,
-                                    ((_("Red or Hue"),          0),
-                                     (_("Green or Saturation"), 1),
-                                     (_("Blue or Value"),       2))),
-        (PF_BOOL,   "ascending", _("_Ascending"), True)
+        (PF_OPTION,   "channel",    _("Channel to _sort"), 3,
+                                    AVAILABLE_CHANNELS),
+        (PF_BOOL,   "ascending", _("_Ascending"), True),
+        (PF_FLOAT,  "granularity", _("_Granularity"), 1.0),
+        (PF_OPTION, "selections", _("Se_lections"), SELECT_ALL,
+                    (_("All"), _("Array"), _("Slice"), _("Partitioned"))),
+        (PF_INT,    "start", _("Selection S_tart"), 0),
+        (PF_INT,    "width", _("Selection _Width"), -1),
+        (PF_INT,    "nrows", _("Selection _Rows"), 1),
+        (PF_OPTION,   "partitionchannel",    _("Channel to _partition by"), 3,
+                                            AVAILABLE_CHANNELS),
+        (PF_FLOAT,  "pgranularity", _("Partition Gra_nularity"), 1.0),
     ],
     [],
     palette_sort,
