Index: extensions/rotateImage/language/en_UK/plugin.lang.php
===================================================================
--- extensions/rotateImage/language/en_UK/plugin.lang.php	(revision 15778)
+++ extensions/rotateImage/language/en_UK/plugin.lang.php	(revision 16973)
@@ -4,6 +4,6 @@
 $lang['Angle'] = 'Angle';
 $lang['Also rotate HD image'] = 'Also rotate HD image';
-$lang['90° right'] = '90° right';
-$lang['90° left'] = '90° left';
+$lang['90° right'] = '90° clockwise';
+$lang['90° left'] = '90° counter-clockwise';
 $lang['180°'] = '180°';
 $lang['auto (EXIF orientation tag)'] = 'auto (EXIF orientation tag)';
Index: extensions/rotateImage/language/fr_FR/plugin.lang.php
===================================================================
--- extensions/rotateImage/language/fr_FR/plugin.lang.php	(revision 15778)
+++ extensions/rotateImage/language/fr_FR/plugin.lang.php	(revision 16973)
@@ -4,6 +4,6 @@
 $lang['Angle'] = 'Angle';
 $lang['Also rotate HD image'] = 'Pivoter aussi l\'image HD';
-$lang['90° right'] = '90° à droite';
-$lang['90° left'] = '90° à gauche';
+$lang['90° right'] = '90° dans le sens des aiguilles d\'une montre';
+$lang['90° left'] = '90° dans le sens inverse des aiguilles d\'une montre';
 $lang['180°'] = '180°';
 $lang['auto (EXIF orientation tag)'] = 'automatique (selon le tag d\'orientation EXIF)';
Index: extensions/rotateImage/main.inc.php
===================================================================
--- extensions/rotateImage/main.inc.php	(revision 15778)
+++ extensions/rotateImage/main.inc.php	(revision 16973)
@@ -2,5 +2,5 @@
 /*
 Plugin Name: Rotate Image
-Version: 0.6
+Version: auto
 Description: enables to rotate images in batch processing
 Plugin URI: http://fr.piwigo.org/ext/extension_view.php?eid=578
@@ -8,8 +8,5 @@
 if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
 
-add_event_handler('loc_begin_element_set_global', 'rotate_image_set_template_data');
 add_event_handler('ws_add_methods', 'add_image_rotate_method');
-add_event_handler('element_set_global_action', 'rotate_image_element_action', 50, 2);
-
 function add_image_rotate_method($arr)
 {
@@ -17,10 +14,14 @@
 }
 
+add_event_handler('loc_begin_element_set_global', 'rotate_image_set_template_data');
 function rotate_image_set_template_data() {
   global $template,$lang;
   load_language('plugin.lang', dirname(__FILE__).'/');
+
+  include_once(PHPWG_ROOT_PATH.'admin/include/image.class.php');
+
   $angles = array (
-    array('value' => 90, 'name' => l10n('90° left')),
     array('value' => 270, 'name' => l10n('90° right')),
+    array('value' =>  90, 'name' => l10n('90° left')),
     array('value' => 180, 'name' => l10n('180°'))
   );
@@ -40,11 +41,30 @@
 }
 
+add_event_handler('element_set_global_action', 'rotate_image_element_action', 50, 2);
 function rotate_image_element_action($action, $collection) {
-  global $template;
   if ($action == 'rotateImg') {
-    //flush thumbnails links by regenerating ramdom ids to uris
-    $template->delete_compiled_templates();
+    add_event_handler('get_derivative_url', 'rotate_image_force_refresh', EVENT_HANDLER_PRIORITY_NEUTRAL, 4);
   }
 }
 
+function rotate_image_force_refresh($root_url, $params, $src_image, $rel_url)
+{
+  global $collection;
+
+  if (in_array($src_image->id, $collection))
+  {
+    if (strpos($root_url, '?') === false)
+    {
+      $root_url.= '?';
+    }
+    else
+    {
+      $root_url.= '&amp;';
+    }
+
+    $root_url.= 'rand='.md5(uniqid(rand(), true));
+  }
+
+  return $root_url;
+}
 ?>
Index: extensions/rotateImage/rotate_image.tpl
===================================================================
--- extensions/rotateImage/rotate_image.tpl	(revision 15778)
+++ extensions/rotateImage/rotate_image.tpl	(revision 16973)
@@ -26,9 +26,8 @@
 
   jQuery('#applyAction').click(function(e) {
-    if (elements.length != 0)
-    {
+    if (typeof(elements) != "undefined") {
       return true;
     }
-    else if (jQuery('[name="selectAction"]').val() == 'rotateImg')
+    if (jQuery('[name="selectAction"]').val() == 'rotateImg')
     {
       angle = jQuery('select[name="rotate_angle"]').val();
@@ -40,4 +39,5 @@
       return true;
     }
+
     jQuery('.bulkAction').hide();
     jQuery('#regenerationText').html(rotateImagesMessage);
@@ -49,4 +49,6 @@
       maxRequests: maxRequests
     });
+
+    elements = Array();
     if (jQuery('input[name="setSelected"]').attr('checked'))
       elements = all_elements;
@@ -83,10 +85,26 @@
         },
         dataType: 'json',
-        success: ( function(data) { progress(++todo, progressBar_max, data['result']) }),
-        error: ( function(data) { progress(++todo, progressBar_max, false) })
+        success: ( function(data) { progressRotate(++todo, progressBar_max, data['result']) }),
+        error: ( function(data) { progressRotate(++todo, progressBar_max, false) })
       });
     }
     return false;
   });
+
+  function progressRotate(val, max, success) {
+    jQuery('#progressBar').progressBar(val, {
+      max: max,
+      textFormat: 'fraction',
+      boxImage: 'themes/default/images/progressbar.gif',
+      barImage: 'themes/default/images/progressbg_orange.gif'
+    });
+    type = success ? 'regenerateSuccess': 'regenerateError'
+    s = jQuery('[name="'+type+'"]').val();
+    jQuery('[name="'+type+'"]').val(++s);
+
+    if (val == max)
+      jQuery('#applyAction').click();
+  }
+
 });
 {/literal}{/footer_script}
Index: extensions/rotateImage/ws_functions.inc.php
===================================================================
--- extensions/rotateImage/ws_functions.inc.php	(revision 15778)
+++ extensions/rotateImage/ws_functions.inc.php	(revision 16973)
@@ -1,4 +1,3 @@
 <?php
-
 if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
 
@@ -34,77 +33,77 @@
   }
 
-  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
+  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
   include_once(PHPWG_ROOT_PATH.'admin/include/image.class.php');
+
   $image_id=(int)$params['image_id'];
   
   $query='
-SELECT id, path, tn_ext, has_high
+SELECT
+    id,
+    path,
+    representative_ext,
+    rotation
   FROM '.IMAGES_TABLE.'
   WHERE id = '.$image_id.'
 ;';
-  $image = pwg_db_fetch_assoc(pwg_query($query));
-  if ($image == null)
+  $row = pwg_db_fetch_assoc(pwg_query($query));
+  if ($row == null)
   {
     return new PwgError(403, "image_id not found");
   }
 
-  // rotation angle
-  if ('auto' == $params['angle']) {
-    $angle = $params['angle'];
+  $base_angle = pwg_image::get_rotation_angle_from_code($row['rotation']);
+
+  if (get_boolean($params['rotate_hd'])) {
+    if ('auto' == $angle) {
+      $angle = pwg_image::get_rotation_angle($row['path']);
+      $rotation_code = 0;
+    }
+    else {
+      // the angle is based on what the user sees (the thumbnail) and not on
+      // the original, which may have a different angle
+      $angle = ($base_angle + $params['angle']) % 360;
+
+      // the derivatives must not be rotated
+      $rotation_code = 4;
+    }
+
+    if (isset($conf['rotate_image_jpegtran']) and $conf['rotate_image_jpegtran']) {
+      $angle = ($angle + 180) % 360;
+      $command = 'jpegtran -copy all -rotate '.$angle.' -outfile '.$row['path'].' '.$row['path'];
+      exec($command);
+    }
+    else {
+      $image = new pwg_image($row['path']);
+      $image->set_compression_quality(98);
+      $image->rotate($angle);
+      $image->write($row['path']);
+    }
+
+    $conf['use_exif'] = false;
+    $conf['use_iptc'] = false;
+    sync_metadata(array($row['id']));
+
+    single_update(
+      IMAGES_TABLE,
+      array('rotation' => $rotation_code),
+      array('id' => $row['id'])
+    );
   }
-  else {
-    $angle = (int)$params['angle'];
+  elseif ('auto' != $params['angle']) {
+    $new_angle = ($base_angle + $params['angle']) % 360;
+    $rotation_code = pwg_image::get_rotation_code_from_angle($new_angle);
+
+    // to show that it's a manual rotation, we use 4,5,6,7 instead of 0,1,2,3
+    $rotation_code+= 4;
+
+    single_update(
+      IMAGES_TABLE,
+      array('rotation' => $rotation_code),
+      array('id' => $row['id'])
+    );
   }
 
-  if (get_boolean($params['rotate_hd']) and get_boolean($image['has_high'])) {
-    $to_rotate_path = file_path_for_type($image['path'], 'high');
-    $quality = $conf['upload_form_hd_quality'];
-    $regenerate_websize = true;
-
-    if ('auto' == $angle) {
-      $angle = pwg_image::get_rotation_angle($to_rotate_path);
-    }
-  }
-  else {
-    $to_rotate_path = $image['path'];
-    $quality = $conf['upload_form_websize_quality'];
-    $regenerate_websize = false;
-  }
-
-  $rotated = new pwg_image($to_rotate_path);
-  $rotated->set_compression_quality($quality);
-  $rotated->rotate($angle);
-  $rotated->write($to_rotate_path);
-
-  if ($regenerate_websize) {
-    ws_images_resizewebsize(
-      array(
-        'image_id' => $params['image_id'],
-        'maxwidth' => $conf['upload_form_websize_maxwidth'],
-        'maxheight' => $conf['upload_form_websize_maxheight'],
-        'quality' => $conf['upload_form_websize_quality'],
-        'automatic_rotation' => $conf['upload_form_automatic_rotation'],
-        'library' => $conf['graphics_library'],
-        ),
-      $service
-      );
-  }
-
-  ws_images_resizethumbnail(
-    array(
-      'image_id' => $params['image_id'],
-      'maxwidth' => $conf['upload_form_thumb_maxwidth'],
-      'maxheight' => $conf['upload_form_thumb_maxheight'],
-      'quality' => $conf['upload_form_thumb_quality'],
-      'crop' => $conf['upload_form_thumb_crop'],
-      'follow_orientation' => $conf['upload_form_thumb_follow_orientation'],
-      'library' => $conf['graphics_library'],
-      ),
-    $service
-    );
-
-  $conf['use_exif'] = false;
-  $conf['use_iptc'] = false;
-  update_metadata(array($image['id'] => $image['path']));
+  delete_element_derivatives($row);
   
   return true;
