Index: /extensions/Ajax_Thumbnailer/admin/js/jquery.ajaxmanager.js
===================================================================
--- /extensions/Ajax_Thumbnailer/admin/js/jquery.ajaxmanager.js	(revision 4549)
+++ /extensions/Ajax_Thumbnailer/admin/js/jquery.ajaxmanager.js	(revision 4549)
@@ -0,0 +1,293 @@
+/**
+ * @author alexander.farkas
+ * 
+ * @version 2.3
+ */
+(function($){
+	
+	$.manageAjax = (function(){
+		var cache 			= {},
+			queues			= {},
+			presets 		= {},
+			activeRequest 	= {},
+			allRequests 	= {},
+			defaults 		= {
+						queue: true, //clear
+						maxRequests: 1,
+						abortOld: false,
+						preventDoubbleRequests: true,
+						cacheResponse: false,
+						complete: function(){},
+						error: function(ahr, status){
+							var opts = this;
+							if(status &&  status.indexOf('error') != -1){
+								setTimeout(function(){
+									var errStr = status +': ';
+									if(ahr.status){
+										errStr += 'status: '+ ahr.status +' | ';
+									}
+									errStr += 'URL: '+ opts.url;
+									throw new Error(errStr);
+								}, 1);
+							}
+						},
+						success: function(){},
+						abort: function(){}
+				}
+		;
+		
+		function create(name, settings){
+			var publicMethods = {};
+			presets[name] = presets[name] ||
+				{};
+			
+			$.extend(true, presets[name], $.ajaxSettings, defaults, settings);
+			if(!allRequests[name]){
+				allRequests[name] 	= {};
+				activeRequest[name] = {};
+				activeRequest[name].queue = [];
+				queues[name] 		= [];
+			}
+			$.each($.manageAjax, function(fnName, fn){
+				if($.isFunction(fn) && fnName.indexOf('_') !== 0){
+					publicMethods[fnName] = function(param){
+						fn(name, param);
+					};
+				}
+			});
+			return publicMethods;
+		}
+		
+		function complete(opts, args){
+			
+			if(args[1] == 'success' || args[1] == 'notmodified'){
+				opts.success.apply(opts, [args[0].successData, args[1]]);
+				if (opts.global) {
+					$.event.trigger("ajaxSuccess", args);
+				}
+			}
+			
+			if(args[1] === 'abort'){
+				opts.abort.apply(opts, args);
+				if(opts.global){
+					$.active--;
+					$.event.trigger("ajaxAbort", args);
+				}
+			}
+			
+			opts.complete.apply(opts, args);
+			
+			if (opts.global) {
+				$.event.trigger("ajaxComplete", args);
+			}
+			
+			if (opts.global && ! $.active){
+				$.event.trigger("ajaxStop");
+			}
+			//args[0] = null; 
+		}
+		
+		function proxy(oldFn, fn){
+			return function(xhr, s, e){
+				fn.call(this, xhr, s, e);
+				oldFn.call(this, xhr, s, e);
+				xhr = null;
+				e = null;
+			};
+		}
+		
+					
+		function callQueueFn(name){
+			var q = queues[name];
+			if(q && q.length){
+				var fn = q.shift();
+				if(fn){
+					fn();
+				}
+			}
+		}
+
+		
+		function add(name, opts){
+			if(!presets[name]){
+				create(name, opts);
+			}
+			opts = $.extend({}, presets[name], opts);
+			//aliases
+			var allR 	= allRequests[name],
+				activeR = activeRequest[name],
+				queue	= queues[name];
+			
+			var id 			= opts.type +'_'+ opts.url.replace(/\./g, '_'),
+				oldComplete = opts.complete,
+				ajaxFn 		= function(){
+								activeR[id] = {
+									xhr: $.ajax(opts),
+									ajaxManagerOpts: opts
+								};
+								activeR.queue.push(id);
+								return id;
+							}
+				;
+				
+			if(opts.data){
+				id += (typeof opts.data == 'string') ? opts.data : $.param(opts.data);
+			}
+			
+			if(opts.preventDoubbleRequests && allRequests[name][id]){
+				return false;
+			}
+			
+			allR[id] = true;
+			
+			opts.complete = function(xhr, s, e){
+				if(opts.abortOld){
+					$.each(activeR.queue, function(i, activeID){
+						if(activeID == id){
+							return false;
+						}
+						abort(name, activeID);
+						return activeID;
+					});
+				}
+				oldComplete.call(this, xhr, s, e);
+				//stop memory leak
+				if(activeRequest[name][id]){
+					if(activeRequest[name][id] && activeRequest[name][id].xhr){
+						activeRequest[name][id].xhr = null;
+					} 
+					activeRequest[name][id] = null;
+				}
+				xhr = null;
+				activeRequest[name].queue = $.grep(activeRequest[name].queue, function(qid){
+					return (qid !== id);
+				});
+				allR[id] = false;
+				e = null;
+				delete activeRequest[name][id];
+			};
+			
+			if(cache[id]){
+				ajaxFn = function(){
+					activeR.queue.push(id);
+					complete(opts, cache[id]);
+					return id;
+				};
+			} else if(opts.cacheResponse){
+				 opts.complete = proxy(opts.complete, function(xhr, s){
+					if( s !== "success" && s !== "notmodified" ){
+						return false;
+					}
+					cache[id][0].responseXML 	= xhr.responseXML;
+					cache[id][0].responseText 	= xhr.responseText;
+					cache[id][1] 				= s;
+					//stop memory leak
+					xhr = null;
+					return id; //strict
+				});
+				
+				opts.success = proxy(opts.success, function(data, s){
+					cache[id] = [{
+						successData: data,
+						ajaxManagerOpts: opts
+					}, s];
+					data = null;
+				});
+			}
+			
+			ajaxFn.ajaxID = id;
+			
+			if(opts.queue){
+				opts.complete = proxy(opts.complete, function(){
+					
+					callQueueFn(name);
+				});
+				 
+				if(opts.queue === 'clear'){
+					queue = clear(name);
+				}
+				
+				queue.push(ajaxFn);
+				
+				if(activeR.queue.length < opts.maxRequests){
+					callQueueFn(name); 
+				}
+				return id;
+			}
+			return ajaxFn();
+		}
+		
+		function clear(name, shouldAbort){
+			$.each(queues[name], function(i, fn){
+				allRequests[name][fn.ajaxID] = false;
+			});
+			queues[name] = [];
+			
+			if(shouldAbort){
+				abort(name);
+			}
+			return queues[name];
+		}
+		
+		function getXHR(name, id){
+			var ar = activeRequest[name];
+			if(!ar || !allRequests[name][id]){
+				return false;
+			}
+			if(ar[id]){
+				return ar[id].xhr;
+			}
+			var queue = queues[name],
+				xhrFn;
+			$.each(queue, function(i, fn){
+				if(fn.ajaxID == id){
+					xhrFn = [fn, i];
+					return false;
+				}
+				return xhrFn;
+			});
+			return xhrFn;
+		}
+		
+		function abort(name, id){
+			var ar = activeRequest[name];
+			if(!ar){
+				return false;
+			}
+			function abortID(qid){
+				if(qid !== 'queue' && ar[qid] && typeof ar[qid].xhr !== 'unedfiend' && typeof ar[qid].xhr.abort !== 'unedfiend'){
+					ar[qid].xhr.abort();
+					complete(ar[qid].ajaxManagerOpts, [ar[qid].xhr, 'abort']);
+				}
+				return null;
+			}
+			if(id){
+				return abortID(id);
+			}
+			return $.each(ar, abortID);
+		}
+		
+		function unload(){
+			$.each(presets, function(name){
+				clear(name, true);
+			});
+			cache = {};
+		}
+		
+		return {
+			defaults: 		defaults,
+			add: 			add,
+			create: 		create,
+			cache: 			cache,
+			abort: 			abort,
+			clear: 			clear,
+			getXHR: 		getXHR,
+			_activeRequest: activeRequest,
+			_complete: 		complete,
+			_allRequests: 	allRequests,
+			_unload: 		unload
+		};
+	})();
+	//stop memory leaks
+	$(window).unload($.manageAjax._unload);
+})(jQuery);
Index: /extensions/Ajax_Thumbnailer/admin/js/thumbnailer.js
===================================================================
--- /extensions/Ajax_Thumbnailer/admin/js/thumbnailer.js	(revision 4549)
+++ /extensions/Ajax_Thumbnailer/admin/js/thumbnailer.js	(revision 4549)
@@ -0,0 +1,58 @@
+var waitingImage = '<img src="'+path+'/admin/img/progress.gif">';
+
+var queuedManager = $.manageAjax.create('queued', { 
+	queue: true,  
+	cacheResponse: false,
+	maxRequests: 5
+}); 
+
+
+function processThumbs(width,height,gd_version) {
+	$('tr.nothumb').each(function() {
+		var file=$(this).find('td.filepath').text();
+		$(this).find('td.thumbpic').html(waitingImage);
+		var td=this;
+		queuedManager.add({
+			type: 'GET', 
+			url: 'ws.php', 
+			data: {method: 'pwg.thumbnail.create',picture:file,format:'json',width: width,height: height, gd_version: gd_version},
+			dataType: 'json',
+			success: (function(row) { return function(data) {
+					if (data.stat =='ok') {
+							$(row).find('td.thumbpic').html('<img src="'+data.result.tn_file+'"/>');
+							$(row).find('td.thumbdim').html(""+data.result.tn_width+"X"+data.result.tn_height);
+							$(row).find('td.thumbgentime').html(""+data.result.tn_time);
+							$(row).find('td.thumbsize').html(""+data.result.tn_size);
+							$(row).removeClass("nothumb");
+						} else {
+							$(row).find('td.thumbpic').html('#ERR#'+data.err+"# : "+data.message);
+							$(row).removeClass("nothumb");
+							$(row).addClass("error");
+						}
+					};})(td)
+			});
+	});
+}
+
+$(document).ready(function(){
+$('input#proceed').click (function () {
+	var width = $('#width')[0].value;
+	var height = $('#height')[0].value;
+	var gd_version=$("input[@name='gd']:checked").val();
+	$("input:not(.nodisable)").attr("disabled",true);
+
+	
+	processThumbs(width,height,gd_version);
+});
+
+$('input#cancel').click (function () {
+	queuedManager.clear();
+	queuedManager.abort();
+	$("input:not(.nodisable)").attr("disabled",false);
+	$('tr.nothumb td.thumbpic').html("&nbsp;");
+	
+});
+$('input#clear').click (function () {
+	$('tr.item:not(.nothumb)').remove();
+});
+});
Index: /extensions/Ajax_Thumbnailer/admin/thumbnailer_admin.php
===================================================================
--- /extensions/Ajax_Thumbnailer/admin/thumbnailer_admin.php	(revision 4549)
+++ /extensions/Ajax_Thumbnailer/admin/thumbnailer_admin.php	(revision 4549)
@@ -0,0 +1,108 @@
+<?php
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+define ('AT_PATH',PHPWG_PLUGINS_PATH . 'AjaxThumbnailer');
+$me = get_plugin_data($plugin_id);
+
+load_language('plugin.lang', AT_PATH.'/');
+ 
+global $template;
+$template->set_filenames( array('plugin_admin_content' => dirname(__FILE__).'/thumbnailer_admin.tpl') );
+// +-----------------------------------------------------------------------+
+// |                   search pictures without thumbnails                  |
+// +-----------------------------------------------------------------------+
+$wo_thumbnails = array();
+$thumbnalized = array();
+
+
+// what is the directory to search in ?
+$query = '
+SELECT galleries_url FROM '.SITES_TABLE.'
+  WHERE galleries_url NOT LIKE "http://%"
+;';
+$result = pwg_query($query);
+while ( $row=mysql_fetch_assoc($result) )
+{
+  $basedir = preg_replace('#/*$#', '', $row['galleries_url']);
+  $fs = get_fs($basedir);
+
+  // because isset is one hundred time faster than in_array
+  $fs['thumbnails'] = array_flip($fs['thumbnails']);
+
+  foreach ($fs['elements'] as $path)
+  {
+    // only pictures need thumbnails
+    if (in_array(get_extension($path), $conf['picture_ext']))
+    {
+      $dirname = dirname($path);
+      $filename = basename($path);
+  
+      // only files matching the authorized filename pattern can be considered
+      // as "without thumbnail"
+      if (!preg_match('/^[a-zA-Z0-9-_.]+$/', $filename))
+      {
+        continue;
+      }
+      
+      // searching the element
+      $filename_wo_ext = get_filename_wo_extension($filename);
+      $tn_ext = '';
+      $base_test = $dirname.'/thumbnail/';
+      $base_test.= $conf['prefix_thumbnail'].$filename_wo_ext.'.';
+      foreach ($conf['picture_ext'] as $ext)
+      {
+        if (isset($fs['thumbnails'][$base_test.$ext]))
+        {
+          $tn_ext = $ext;
+          break;
+        }
+      }
+      
+      if (empty($tn_ext))
+      {
+        array_push($wo_thumbnails, $path);
+      }
+    }
+  } // next element
+} // next site id
+
+  $form_url = get_root_url().'admin.php?page=thumbnail';
+  $gd = !empty($_POST['gd']) ? $_POST['gd'] : 2;
+  $width = !empty($_POST['width']) ? $_POST['width'] : $conf['tn_width'];
+  $height = !empty($_POST['height']) ? $_POST['height'] : $conf['tn_height'];
+  $n = !empty($_POST['n']) ? $_POST['n'] : 5;
+  
+  $template->assign(
+    'params',
+    array(
+      'F_ACTION'=> $form_url,
+      'GD_SELECTED' => $gd,
+      'N_SELECTED' => $n,
+      'WIDTH_TN'=>$width,
+      'HEIGHT_TN'=>$height,
+      ));
+
+  $template->assign(
+    'TOTAL_NB_REMAINING',
+    count($wo_thumbnails));
+  $template->assign(
+    'plugin',
+    array(
+		'path' => AT_PATH
+	));
+
+  foreach ($wo_thumbnails as $path)
+  {
+    list($width, $height) = getimagesize($path);
+    $size = floor(filesize($path) / 1024).' KB';
+
+    $template->append(
+      'wo_thumbnails',
+      array(
+        'PATH'=>$path,
+        'FILESIZE_IMG'=>$size,
+        'WIDTH_IMG'=>$width,
+        'HEIGHT_IMG'=>$height,
+        ));
+  }
+ $template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
+?>
Index: /extensions/Ajax_Thumbnailer/admin/thumbnailer_admin.tpl
===================================================================
--- /extensions/Ajax_Thumbnailer/admin/thumbnailer_admin.tpl	(revision 4549)
+++ /extensions/Ajax_Thumbnailer/admin/thumbnailer_admin.tpl	(revision 4549)
@@ -0,0 +1,81 @@
+<script type="text/javascript">
+	var path="{$plugin.path}";
+</script>
+<script type="text/javascript" src="{$plugin.path}/admin/js/jquery.ajaxmanager.js"></script>
+<script type="text/javascript" src="{$plugin.path}/admin/js/thumbnailer.js"></script>
+
+<div class="titrePage">
+  <h2>{'title_thumbnails'|@translate}</h2>
+</div>
+
+
+{if isset($params) }
+<form method="post" action="{$params.F_ACTION}" class="properties">
+
+  <fieldset>
+    <legend>{'tn_params_title'|@translate}</legend>
+
+    <ul>
+      <li>
+        <span class="property">{'tn_params_GD'|@translate}</span>
+	<label>
+          <input type="radio" name="gd" value="2" {if $params.GD_SELECTED==2}checked="checked"{/if}>2.x
+        </label>
+        <label>
+          <input type="radio" name="gd" value="1" {if $params.GD_SELECTED==1}checked="checked"{/if}>1.x
+        </label>
+      </li>
+
+      <li>
+        <span class="property">
+          <label for="width">{'maximum width'|@translate}</label>
+        </span>
+	<input type="text" id="width" name="width" value="{$params.WIDTH_TN}">
+      </li>
+
+      <li>
+        <span class="property">
+          <label for="height">{'maximum height'|@translate}</label>
+        </span>
+	<input type="text" id="height" name="height" value="{$params.HEIGHT_TN}">
+      </li>
+    </ul>
+  </fieldset>
+
+  <p><input type="button" name="submit" id="proceed" value="{'Submit'|@translate}" {$TAG_INPUT_ENABLED}>
+  <input type="button" class="nodisable" name="submit" id="cancel" value="{'Cancel'|@translate}" {$TAG_INPUT_ENABLED}>
+  <input type="button" class="nodisable" name="submit" id="clear" value="{'clear_success'|@translate}" {$TAG_INPUT_ENABLED}>
+  
+  </p>
+</form>
+{/if} {*isset params*}
+
+{if !empty($wo_thumbnails) }
+<div class="admin">{$TOTAL_NB_REMAINING} {'tn_alone_title'|@translate}</div>
+<table style="width:100%;">
+  <tr class="throw">
+    <td>&nbsp;</td>
+    <td style="width:60%;">{'Path'|@translate}</td>
+    <td>{'filesize'|@translate}</td>
+    <td>{'Dimensions'|@translate}</td>
+    <td>{'thumbnail'|@translate}</td>
+    <td>{'tn_results_gen_time'|@translate}</td>
+    <td>{'filesize'|@translate}</td>
+    <td>{'Dimensions'|@translate}</td>
+  </tr>
+  {foreach from=$wo_thumbnails item=elt name=remain_loop}
+  <tr class="{if $smarty.foreach.remain_loop.index is odd}row1{else}row2{/if} nothumb item" id="th_{$smarty.foreach.remain_loop.iteration}">
+    <td>{$smarty.foreach.remain_loop.iteration}</td>
+    <td class="filepath">{$elt.PATH}</div></td>
+    <td>{$elt.FILESIZE_IMG}</div></td>
+    <td>{$elt.WIDTH_IMG} x {$elt.HEIGHT_IMG}</td>
+	<td class="thumbpic">&nbsp;</td>
+	<td class="thumbgentime">&nbsp;</td>
+	<td class="thumbsize">&nbsp;</td>
+	<td class="thumbdim">&nbsp;</td>
+  </tr>
+  {/foreach}
+</table>
+{else}
+<div style="text-align:center;font-weight:bold;margin:10px;"> [ {'tn_no_missing'|@translate} ]</div>
+{/if}
Index: /extensions/Ajax_Thumbnailer/language/en_UK/index.php
===================================================================
--- /extensions/Ajax_Thumbnailer/language/en_UK/index.php	(revision 4549)
+++ /extensions/Ajax_Thumbnailer/language/en_UK/index.php	(revision 4549)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based picture gallery                                  |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2009 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/Ajax_Thumbnailer/language/en_UK/plugin.lang.php
===================================================================
--- /extensions/Ajax_Thumbnailer/language/en_UK/plugin.lang.php	(revision 4549)
+++ /extensions/Ajax_Thumbnailer/language/en_UK/plugin.lang.php	(revision 4549)
@@ -0,0 +1,28 @@
+﻿<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based picture gallery                                  |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2009 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+
+$lang['clear_success'] = 'Clear successful processes';
+
+
+?>
Index: /extensions/Ajax_Thumbnailer/language/fr_FR/index.php
===================================================================
--- /extensions/Ajax_Thumbnailer/language/fr_FR/index.php	(revision 4549)
+++ /extensions/Ajax_Thumbnailer/language/fr_FR/index.php	(revision 4549)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based picture gallery                                  |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2009 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/Ajax_Thumbnailer/language/fr_FR/plugin.lang.php
===================================================================
--- /extensions/Ajax_Thumbnailer/language/fr_FR/plugin.lang.php	(revision 4549)
+++ /extensions/Ajax_Thumbnailer/language/fr_FR/plugin.lang.php	(revision 4549)
@@ -0,0 +1,29 @@
+﻿<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based picture gallery                                  |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2009 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+
+$lang['Cancel'] = 'Annuler';
+$lang['clear_success'] = 'Effacer les traitements réussis';
+
+
+?>
Index: /extensions/Ajax_Thumbnailer/main.inc.php
===================================================================
--- /extensions/Ajax_Thumbnailer/main.inc.php	(revision 4549)
+++ /extensions/Ajax_Thumbnailer/main.inc.php	(revision 4549)
@@ -0,0 +1,160 @@
+<?php
+/*
+Plugin Name: Ajax Thumbnailer
+Version: 0.3
+Description: gestion de miniatures en masse / mass thumbnail generator
+Plugin URI: http://piwigo.org/ext/extension_view.php?eid=327
+Author: Bruno Hondelatte
+Author URI: http://morefnu.org
+*/
+
+ini_set('error_reporting', E_ALL);
+ini_set('display_errors', true);
+
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+class AjaxThumbnailer
+{
+	/* This function is almost the same as the ont in admin/thumbnail.php , tuned
+		for web-service purposes */
+	function RatioResizeImg($path, $newWidth, $newHeight, $tn_ext,$gd_version=2) {
+		global $conf, $lang, $page;
+		
+		$starttime = get_moment();
+
+		if (!function_exists('gd_info'))
+			return new PwgError(WS_ERR_INVALID_PARAM,  'no gd');
+
+		if (!file_exists($path))
+			return new PwgError(WS_ERR_INVALID_PARAM,  'file not found');
+
+		$filename = basename($path);
+		$dirname = dirname($path);
+
+		// extension of the picture filename
+		$extension = get_extension($filename);
+
+		if (in_array($extension, array('jpg', 'JPG', 'jpeg', 'JPEG'))) {
+			$srcImage = @imagecreatefromjpeg($path);
+		}
+		elseif ($extension == 'png' or $extension == 'PNG') {
+			$srcImage = @imagecreatefrompng($path);
+		} else {
+			unset($extension);
+		}
+
+		if ( isset( $srcImage ) ) {
+			// width/height
+			$srcWidth    = imagesx( $srcImage ); 
+			$srcHeight   = imagesy( $srcImage ); 
+			$ratioWidth  = $srcWidth/$newWidth;
+			$ratioHeight = $srcHeight/$newHeight;
+
+			// maximal size exceeded ?
+			if ( ( $ratioWidth > 1 ) or ( $ratioHeight > 1 ) ) {
+				if ( $ratioWidth < $ratioHeight) { 
+					$destWidth = $srcWidth/$ratioHeight;
+					$destHeight = $newHeight; 
+				} else { 
+					$destWidth = $newWidth; 
+					$destHeight = $srcHeight/$ratioWidth;
+				}
+			} else {
+				$destWidth = $srcWidth;
+				$destHeight = $srcHeight;
+			}
+			// according to the GD version installed on the server
+			if ( $gd_version == 2 ) {
+				// GD 2.0 or more recent -> good results (but slower)
+				$destImage = imagecreatetruecolor( $destWidth, $destHeight); 
+				imagecopyresampled( $destImage, $srcImage, 0, 0, 0, 0,
+					$destWidth,$destHeight,$srcWidth,$srcHeight );
+			} else {
+				// GD prior to version  2 -> pretty bad results :-/ (but fast)
+				$destImage = imagecreate( $destWidth, $destHeight);
+				imagecopyresized( $destImage, $srcImage, 0, 0, 0, 0,
+					$destWidth,$destHeight,$srcWidth,$srcHeight );
+			}
+
+			if (($tndir = mkget_thumbnail_dir($dirname)) == false) {
+				return new PwgError(WS_ERR_INVALID_PARAM,  '['.$tndir.'] : '.l10n('no_write_access'));
+			}
+
+			$dest_file = $tndir.'/'.$conf['prefix_thumbnail'];
+			$dest_file.= get_filename_wo_extension($filename);
+			$dest_file.= '.'.$tn_ext;
+
+			// creation and backup of final picture
+			if (!is_writable($tndir))
+				return new PwgError(WS_ERR_INVALID_PARAM,  '['.$tndir.'] : '.l10n('no_write_access'));
+				
+			imagejpeg($destImage, $dest_file, $conf['tn_compression_level']);
+			// freeing memory ressources
+			imagedestroy( $srcImage );
+			imagedestroy( $destImage );
+
+			list($tn_width, $tn_height) = getimagesize($dest_file);
+			$tn_size = floor(filesize($dest_file) / 1024).' KB';
+
+			$endtime = get_moment();
+			
+			$info = array( 'path'      => $path,
+			'tn_file'   => $dest_file,
+			'tn_width'  => $tn_width,
+			'tn_height' => $tn_height,
+			'tn_size'   => $tn_size,
+			'tn_time'	=> number_format(($endtime - $starttime) * 1000, 2, '.', ' ').' ms');
+			return $info;
+		} else {
+			// error
+			$err=l10n('tn_no_support');
+			if ( isset( $extension ) )
+				$err .= l10n('tn_format').' '.$extension;
+			else
+				$err .= l10n('tn_thisformat');
+			return new PwgError(WS_ERR_INVALID_PARAM, $err);
+		}
+	}
+
+	function plugin_admin_menu($menu) {
+        array_push($menu,
+            array(
+                'NAME' => 'Ajax Thumbnailer',
+                'URL' => get_admin_plugin_menu_link(dirname(__FILE__).'/admin/thumbnailer_admin.php')
+            )
+        );
+        return $menu;
+    }
+
+	function ws_methods($arr) {
+		$service = &$arr[0];
+		$service->addMethod('pwg.thumbnail.create', array($this,'create_thumb'),
+		  array(
+			'picture'=>array(),
+			'width'=>array('default'=>"128"),
+			'height'=>array('default'=>"128"),
+			'ext'=>array('default'=>"jpg")
+		  ),
+		  'Creates a thumbnail for a given image,
+		<br><b>picture</b> is the name of the picture to create thumbnail from.'
+		);
+		
+	}
+	
+	function create_thumb($params, $service) {
+		$picture = $params['picture'];
+		$width = (integer)$params['width'];
+		$height = (integer)$params['height'];
+		$gd_version = (integer)$params['gd_version'];		
+		$ext =$params['ext'];
+		return $this->RatioResizeImg($picture,$width,$height,$ext,$gd_version);
+	}
+	
+}
+$obj = new AjaxThumbnailer();
+
+add_event_handler('ws_add_methods', array(&$obj, 'ws_methods'));
+add_event_handler('get_admin_plugin_menu_links', array(&$obj, 'plugin_admin_menu') );
+set_plugin_data($plugin['id'], $obj);
+
+?>
