diff --git a/coloractions/imagecache_coloractions.module b/coloractions/imagecache_coloractions.module
index 3a9297b..4057c59 100755
--- a/coloractions/imagecache_coloractions.module
+++ b/coloractions/imagecache_coloractions.module
@@ -89,6 +89,15 @@ function imagecache_coloractions_image_effect_info() {
     'summary theme' => 'coloractions_alpha_summary',
   );
 
+  $effects['coloractions_posterize'] = array(
+    'label' => t('Posterize'),
+    'help' => t('Reduce number of colors per channel in image.'),
+    'effect callback' => 'coloractions_posterize_image',
+    'dimensions passthrough' => TRUE,
+    'form callback' => 'coloractions_posterize_form',
+    'summary theme' => 'coloractions_posterize_summary',
+  );
+  
   return $effects;
 }
 
@@ -112,6 +121,9 @@ function imagecache_coloractions_theme() {
     'coloractions_convert_summary' => array(
       'variables' => array('data' => NULL),
     ),
+    'coloractions_posterize_summary' => array(
+      'variables' => array('data' => NULL),
+    ),
   );
 }
 
@@ -497,3 +509,88 @@ function coloractions_file_formats() {
   return array('image/jpeg' => 'jpg', 'image/gif' => 'gif', 'image/png' => 'png');
 }
 
+/**
+ * Implementation of theme_hook() for imagecache_ui.module
+ */
+function theme_coloractions_posterize_summary($variables) {
+  return t(': Reduce to @colors colors per channel @withDithering', array('@colors' => $variables['data']['colors'], '@with' => $variables['data']['dither'] ? '+' : '-'));
+}
+
+function coloractions_posterize_image(&$image, $data) {
+  if (!image_toolkit_invoke('posterize', $image, array($data['colors'], $data['dither']))) {
+    watchdog('image_posterize', 'Image posterize failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array(
+      '%toolkit' => $image->toolkit,
+      '%path' => $image->source,
+      '%mimetype' => $image->info['mime_type'],
+      '%dimensions' => $image->info['height'] . 'x' . $image->info['height'],
+    ), WATCHDOG_ERROR);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+function coloractions_posterize_form($data) {
+  $form = array();
+  
+  $form['colors'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Colors per channel'),
+    '#default_value' => isset($data['colors']) ? $data['colors'] : '',
+    '#required' => TRUE,
+    '#size' => 10,
+    '#element_validate' => array('image_effect_integer_validate'),
+    '#allow_negative' => FALSE,
+    '#description' => t('Number of unique colors per channel to reduce this image to.'),
+  );
+  
+  $form['dither'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Dither'),
+    '#default_value' => isset($data['dither']) ? $data['dither'] : FALSE,
+    '#return_value' => TRUE,
+    '#description' => t('This will give the illusion of smoother color graduations. It is not recommended if you are using this effect for file size reduction.'),
+  );
+  
+  return $form;
+}
+
+/**
+ * 
+ * @see http://php.net/manual/en/function.imagetruecolortopalette.php#44803
+ */
+function image_gd_posterize(stdClass $image, $colors, $dither = FALSE) {
+  
+  // Value step for colors per channel.
+  $round_to = 255 / ($colors - 1);
+  
+  for ($x=imagesx($image->resource); $x--; ) {
+    for ($y=imagesy($image->resource); $y--; ) {
+      
+      $rgb = imagecolorat($image->resource, $x, $y);
+      
+      // Use bitmasks to extract numbers we want, faster equivalent to imagecolorsforindex().
+      $alpha = $rgb >> 24;
+      $red = ($rgb & ~4278255615) >> 16; // 4278255615 = (255 << 24 | 255 << 8 | 255)
+      $green = ($rgb & ~4294902015)  >> 8; // 4294902015 = (255 << 24 | 255 << 16 | 255)
+      $blue = $rgb & ~4294967040; // 4294967040 = (255 << 24 | 255 << 16 | 255 << 8)
+      
+      $new_red = (int) (((int) ($red / $round_to + 0.5)) * $round_to  + 0.5);
+      $new_green = (int) (((int) ($green / $round_to + 0.5)) * $round_to  + 0.5);
+      $new_blue = (int) (((int) ($blue / $round_to + 0.5)) * $round_to  + 0.5);
+      
+      // Faster equivalent to imagecolorallocatealpha().
+      $color_combined = ($alpha << 24) | ($new_red << 16) | ($new_green << 8) | $new_blue;
+      
+      imagesetpixel($image->resource, $x, $y, $color_combined);
+    }
+  }
+  
+  return TRUE;
+}
+
+function image_imagemagick_posterize(stdClass $image, $colors, $dither = FALSE) {
+  
+  // Dithering is on by default, so +dither disables dithering in ImageMagick.
+  $image->ops[] = (!$dither ? '+dither ' : '') . '-posterize ' . (int) $colors;
+  return TRUE;
+}
