Index: /extensions/ColorStat/admin/cstat_admin.tpl
===================================================================
--- /extensions/ColorStat/admin/cstat_admin.tpl	(revision 5961)
+++ /extensions/ColorStat/admin/cstat_admin.tpl	(revision 5961)
@@ -0,0 +1,9 @@
+<h2 style="float:right;top:-24px;position:relative;height:auto;font-size:12px;font-weight:normal;">{$plugin.CSTAT_VERSION}</h2>
+
+<div style="position:relative;top:-24px;clear:right;">
+
+</div>
+
+
+{$CSTAT_BODY_PAGE}
+
Index: /extensions/ColorStat/admin/cstat_config.tpl
===================================================================
--- /extensions/ColorStat/admin/cstat_config.tpl	(revision 5961)
+++ /extensions/ColorStat/admin/cstat_config.tpl	(revision 5961)
@@ -0,0 +1,1 @@
+<h2>{'cstat_config_plugin'|@translate}</h2>
Index: /extensions/ColorStat/admin/cstat_database.tpl
===================================================================
--- /extensions/ColorStat/admin/cstat_database.tpl	(revision 5961)
+++ /extensions/ColorStat/admin/cstat_database.tpl	(revision 5961)
@@ -0,0 +1,266 @@
+{known_script id="jquery.ui" src=$ROOT_URL|@cat:"themes/default/js/ui/packed/ui.core.packed.js"}
+{known_script id="jquery.ui.dialog" src=$ROOT_URL|@cat:"themes/default/js/ui/packed/ui.dialog.packed.js"}
+
+
+{literal}
+<script type="text/javascript">
+var processAnalyze = {
+      step:0,
+      lists:new Array(),
+      timeStart:0,
+      timeEnd:0
+    }
+
+  function init()
+  {
+    getStatus();
+  }
+
+  function getStatus()
+  {
+    data=$.ajax(
+      {
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: false,
+        data: { ajaxfct:"updateDatabaseGetStatus" }
+      }
+    ).responseText;
+
+    list=data.split(";");
+    $("#ianalyzestatus").html("<ul><li>"+list[0]+"</li><li>"+list[1]+"</li><li>"+list[2]+"</li></ul>");
+  }
+
+
+  function doAnalyze()
+  {
+    mode="all";
+    modeLabel="";
+
+    if($("#ianalyze_action0").get(0).checked)
+    {
+      mode="notAnalyzed";
+      modeLabel="{/literal}{'cstat_analyze_not_analyzed_pictures'|@translate}{literal}";
+    }
+    else if($("#ianalyze_action1").get(0).checked)
+    {
+      mode="all";
+      modeLabel="{/literal}{'cstat_analyze_all_pictures'|@translate}{literal}";
+    }
+    else if($("#ianalyze_action2").get(0).checked)
+    {
+      mode="caddieAdd";
+      modeLabel="{/literal}{'cstat_analyze_caddie_add_pictures'|@translate}{literal}";
+    }
+    else if($("#ianalyze_action3").get(0).checked)
+    {
+      mode="caddieReplace";
+      modeLabel="{/literal}{'cstat_analyze_caddie_replace_pictures'|@translate}{literal}";
+    }
+
+
+    doAnalyze="<br><form id='iDialogProgress' class='formtable'>"+
+      "<div id='iprogressbar_contener' class='gcBorderInput'>"+
+      "<span id='iprogressbar_bg' class='gcBgInput' style='width:0%;'>&nbsp;</span>"+
+      "<span id='iprogressbar_fg' class='gcLink'>0%</span>"+
+      "</div><p>{/literal}{'cstat_analyze_in_progress'|@translate}{literal}"+
+      "<br><img src='./plugins/GrumPluginClasses/icons/processing.gif'>"
+      "</p></form>";
+
+
+    $("#dialog")
+    .html("")
+    .dialog(
+      {
+        resizable: false,
+        width:480,
+        height:120,
+        modal: true,
+        draggable:true,
+        dialogClass: 'gcBgTabSheet gcBorder',
+        title: '{/literal}{"cstat_updating_database"|@translate}{literal}&nbsp;('+modeLabel+')',
+      }
+    ).html(doAnalyze);
+
+    NumberOfItemsPerRequest=$("#iNumberOfItemsPerRequest").val();
+
+    $.ajax(
+      {
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: true,
+        data: { ajaxfct:"updateDatabaseGetList", selectMode:mode, numOfItems:NumberOfItemsPerRequest },
+        success: function(msg)
+          {
+            processAnalyze.step=0;
+            processAnalyze.lists=msg.split(";");
+            processAnalyze.timeStart=new Date();
+            doStep_processList();
+          },
+        error: function()
+          {
+            alert('error');
+          }
+      }
+    );
+  }
+
+
+  function displayTime(eTime)
+  {
+    seconds=(eTime%60).toFixed(2);
+    minutes=((eTime-seconds)/60).toFixed(0);
+    returned=seconds+"s";
+    if(minutes>0) returned=minutes+"m"+returned;
+    return(returned);
+  }
+
+  function doStep_processList()
+  {
+    if(processAnalyze.step < processAnalyze.lists.length)
+    {
+      tmp = $.ajax(
+      {
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: true,
+        data: { ajaxfct:"updateDatabaseDoAnalyze", imagesList:processAnalyze.lists[processAnalyze.step] },
+        success: function(msg)
+          {
+            processAnalyze.step++;
+            doStep_processList();
+          },
+       });
+
+      pct=100*(processAnalyze.step+1)/processAnalyze.lists.length;
+      $("#iprogressbar_bg").css("width", pct+"%");
+      $("#iprogressbar_fg").html(Math.round(pct)+"%");
+    }
+    else
+    {
+      // list completely processed
+      tmp = $.ajax({
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: false,
+        data: { ajaxfct:"updateDatabaseConsolidation" }
+       }).responseText;
+
+
+      processAnalyze.timeEnd = new Date();
+      timeElapsed=processAnalyze.timeEnd.getTime()-processAnalyze.timeStart.getTime();
+
+      $("#dialog")
+      .dialog("destroy")
+      .html("")
+      .get(0).removeAttribute('style');
+
+      $("#dialog")
+      .dialog(
+        {
+          resizable: false,
+          width:480,
+          height:120,
+          modal: true,
+          draggable:true,
+          dialogClass: 'gcBgTabSheet gcBorder',
+          title: '{/literal}{"cstat_updating_database"|@translate}{literal}',
+          dialogClass: 'gcBgTabSheet gcBorder',
+          open: function(event, ui)
+          {
+            bH=$("div.ui-dialog-buttonpane").get(0).clientHeight;
+            $("#dialog").css('height', (this.clientHeight-bH)+"px");
+          },
+          buttons:
+          {
+            '{/literal}{"cstat_ok"|@translate}{literal}':
+              function()
+              {
+                $(this).dialog('destroy').html("").get(0).removeAttribute('style');
+              }
+          }
+        }
+      )
+      .html("<br>{/literal}{'cstat_analyze_is_finished'|@translate}{literal}&nbsp;("+displayTime(timeElapsed/1000)+")");
+
+      getStatus();
+    }
+  }
+
+
+
+</script>
+{/literal}
+
+<h2>{'cstat_status_of_database'|@translate}</h2>
+
+<div id="dialog"></div>
+
+
+<div id="ianalyzestatus">
+  <ul>
+    <li>{'cstat_loading'|@translate}</li>
+    <li>{'cstat_loading'|@translate}</li>
+    <li>{'cstat_loading'|@translate}</li>
+  </ul>
+</div>
+
+
+<div id='ianalyzearea'>
+  <fieldset>
+    <legend>{'cstat_update_color_database'|@translate}</legend>
+      <form class="formtable">
+        <div class="nfo">
+          <p>{'cstat_need_to_analyze'|@translate}</p>
+        </div>
+
+        <label>
+          <input type="radio" value="caddieAdd" name="fAMD_analyze_action" id="ianalyze_action2" checked>&nbsp;
+          {'cstat_analyze_caddie_add_pictures'|@translate}
+        </label><br>
+
+        <label>
+          <input type="radio" value="caddieReplace" name="fAMD_analyze_action" id="ianalyze_action3">&nbsp;
+          {'cstat_analyze_caddie_replace_pictures'|@translate}
+        </label><br>
+
+
+        <label>
+          <input type="radio" value="notAnalayzed" name="fAMD_analyze_action" id="ianalyze_action0">&nbsp;
+          {'cstat_analyze_not_analyzed_pictures'|@translate}
+        </label><br>
+
+        <label>
+          <input type="radio" value="all" name="fAMD_analyze_action" id="ianalyze_action1">&nbsp;
+          {'cstat_analyze_all_pictures'|@translate}
+        </label><br>
+
+        <div class="warning">
+          <p style="font-weight:bold; font-size:+2;">{'cstat_warning_on_analyze_0'|@translate}</p>
+          <p>{'cstat_warning_on_analyze_1'|@translate}</p>
+          <p  style="font-weight:bold;">{'cstat_warning_on_analyze_2'|@translate}</p>
+        </div>
+
+
+        <br>
+        <input type="hidden" id="iNumberOfItemsPerRequest" value="{$datas.numberOfItemsPerRequest}">
+        <!--
+        {'cstat_setting_nb_items_per_request'|@translate}&nbsp;
+        <div id="iamd_nb_item_per_request_slider"></div>
+        <div id="iamd_nb_item_per_request_display"></div>
+        <br><br>
+        -->
+
+        <input type="button" value="{'cstat_analyze'|@translate}" onclick="doAnalyze();">
+
+      </form>
+  </fieldset>
+
+</div>
+
+
+
+
+<script type="text/javascript">
+  init();
+</script>
Index: /extensions/ColorStat/admin/cstat_install_page.tpl
===================================================================
--- /extensions/ColorStat/admin/cstat_install_page.tpl	(revision 5961)
+++ /extensions/ColorStat/admin/cstat_install_page.tpl	(revision 5961)
@@ -0,0 +1,124 @@
+{literal}
+<script type="text/javascript">
+var tableSize='small';
+
+  function displayTable(size)
+  {
+    if(size=='small')
+    {
+      $("#iSmallColorTable").css('display', 'block');
+      $("#iLargeColorTable").css('display', 'none');
+    }
+    else
+    {
+      $("#iSmallColorTable").css('display', 'none');
+      $("#iLargeColorTable").css('display', 'block');
+    }
+    tableSize=size;
+  }
+
+  function submitForm()
+  {
+    $.ajax(
+      {
+        type: "POST",
+        url: "{/literal}{$urlRequest}{literal}",
+        async: true,
+        data: { ajaxfct:"installProcess", tableSize:tableSize },
+        success:
+          function(msg)
+          {
+            window.location=document.URL; //just reload the page...
+          }
+      }
+    );
+
+  }
+
+</script>
+{/literal}
+
+<form id="iSteps" method="post" action="" class="general">
+
+  <fieldset id="iStep1">
+    <legend>{'cstat_step_1'|@translate}</legend>
+
+    <p>{$help.Step1}</p>
+
+    <label><input type="radio" onclick="displayTable('small');" name="f_tablesize" name="iTableSizeSmall" value="small" checked> {'cstat_small_colortable'|@translate}</label><br>
+    <label><input type="radio" onclick="displayTable('large');" name="f_tablesize" name="iTableSizeLarge" value="large"> {'cstat_large_colortable'|@translate}</label>
+
+    <div id="iSmallColorTable">
+      <table>
+        <tr>
+          <td style="min-width:450px;">{$smallTableColor}</td>
+
+          <td style='padding-left:30px;vertical-align:top;'>
+            <p>{$help.SmallColorTable}</p>
+            <br>
+            <table>
+              <tr>
+                <td><img src="./plugins/ColorStat/image/sample1.png"></td>
+                <td style="width:20px;">&nbsp;</td>
+                <td><img src="./plugins/ColorStat/image/sample2.png"></td>
+              </tr>
+
+              <tr>
+                <td>
+                  {'cstat_sample_color_associated'|@translate}
+                  {$smallColorList1}
+                </td>
+                <td style="width:20px;">&nbsp;</td>
+                <td>
+                  {'cstat_sample_color_associated'|@translate}
+                  {$smallColorList2}
+                </td>
+              </tr>
+            </table>
+
+          </td>
+        </tr>
+      </table>
+    </div>
+
+    <div id="iLargeColorTable" style="display:none;">
+      <table>
+        <tr>
+          <td style="min-width:450px;">{$largeTableColor}</td>
+
+          <td style='padding-left:30px;vertical-align:top;'>
+            <p>{$help.LargeColorTable}</p>
+            <br>
+            <table>
+              <tr>
+                <td><img src="./plugins/ColorStat/image/sample1.png"></td>
+                <td style="width:20px;">&nbsp;</td>
+                <td><img src="./plugins/ColorStat/image/sample2.png"></td>
+              </tr>
+
+              <tr>
+                <td>
+                  {'cstat_sample_color_associated'|@translate}
+                  {$largeColorList1}
+                </td>
+                <td style="width:20px;">&nbsp;</td>
+                <td>
+                  {'cstat_sample_color_associated'|@translate}
+                  {$largeColorList2}
+                </td>
+              </tr>
+            </table>
+
+          </td>
+        </tr>
+      </table>
+    </div>
+
+  </fieldset>
+
+  <input type="button" onclick='submitForm();'  value="{'cstat_validate'|@translate}">
+
+</form>
+
+
+
Index: /extensions/ColorStat/admin/cstat_search.tpl
===================================================================
--- /extensions/ColorStat/admin/cstat_search.tpl	(revision 5961)
+++ /extensions/ColorStat/admin/cstat_search.tpl	(revision 5961)
@@ -0,0 +1,1 @@
+<h2>{'cstat_search_by_color'|@translate}</h2>
Index: /extensions/ColorStat/admin/cstat_stat.tpl
===================================================================
--- /extensions/ColorStat/admin/cstat_stat.tpl	(revision 5961)
+++ /extensions/ColorStat/admin/cstat_stat.tpl	(revision 5961)
@@ -0,0 +1,112 @@
+
+{literal}
+<script type="text/javascript">
+
+  function init()
+  {
+    loadColorList();
+    displayColorListOrder();
+  }
+
+  function loadColorList()
+  {
+    order=$('#iSelectOrderColorList').val();
+
+    $("#iListColors").html("<br>{/literal}{'cstat_loading'|@translate}{literal}<br><img src='./plugins/GrumPluginClasses/icons/processing.gif'>");
+
+    $.ajax(
+      {
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: true,
+        data: { ajaxfct:"showStatsGetListColors", orderType:order },
+        success:
+          function(msg)
+          {
+            $("#iListColors").html(msg);
+
+            $("#iListColorsNb").html(
+              "{/literal}{'cstat_number_of_colors_used'|@translate}{literal}&nbsp;"+$("#iListColors table tr").length
+            );
+          }
+      }
+    );
+  }
+
+  function sortColorList(by)
+  {
+    $("#iSelectOrderColorList").val(by);
+    displayColorListOrder();
+    loadColorList();
+  }
+
+  function displayColorListOrder()
+  {
+    if($("#iSelectOrderColorList").val()=="color")
+    {
+      $("#iHLTOrderColor").html("&#8593;");
+      $("#iHLTOrderNumImages").html("");
+      $("#iHLTOrderNumPixels").html("");
+    }
+    else if($("#iSelectOrderColorList").val()=="img")
+    {
+      $("#iHLTOrderColor").html("");
+      $("#iHLTOrderNumImages").html("&#8593;");
+      $("#iHLTOrderNumPixels").html("");
+    }
+    else if($("#iSelectOrderColorList").val()=="pixel")
+    {
+      $("#iHLTOrderColor").html("");
+      $("#iHLTOrderNumImages").html("");
+      $("#iHLTOrderNumPixels").html("&#8593;");
+    }
+  }
+
+
+</script>
+{/literal}
+
+<h2>{'cstat_statistics'|@translate}</h2>
+
+<form>
+  <input type="hidden" id="iSelectOrderColorList" value="{$datas.config_GetListColors_OrderType}"/>
+</form>
+
+<table style="width:100%;">
+  <tr>
+    <td style="min-width:300px;">
+      {$datas.colorTable}
+    </td>
+
+    <td style="width:8px;"></td>
+
+    <td>
+
+      <table id='iHeaderListColors' class="littlefont">
+        <tr>
+          <th style="min-width:180px;" colspan="2"><span id="iHLTOrderColor"></span><a onclick="sortColorList('color');">{'cstat_colors'|@translate}</a></th>
+
+          <th width="60px"><span id="iHLTOrderNumImages"></span><a onclick="sortColorList('img');" title="{'cstat_NumOfImages_help'|@translate}">{'cstat_NumOfImages'|@translate}</a></th>
+          <th width="40px">{'cstat_Pct'|@translate}</th>
+          <th width="115px">&nbsp;</th>
+
+          <th width="80px"><span id="iHLTOrderNumPixels"></span><a onclick="sortColorList('pixels');" title="{'cstat_NumOfPixels_help'|@translate}">{'cstat_NumOfPixels'|@translate}</a></th>
+          <th width="40px">{'cstat_Pct'|@translate}</th>
+          <th width="130px">&nbsp;</th>
+        </tr>
+      </table>
+      <div id='iListColors' class="{$themeconf.name}">
+      </div>
+      <div id="iListColorsNb"></div>
+    </td>
+  </tr>
+
+</table>
+
+
+
+
+
+<script type="text/javascript">
+  init();
+</script>
Index: /extensions/ColorStat/admin/cstat_stat_show_iListColors.tpl
===================================================================
--- /extensions/ColorStat/admin/cstat_stat_show_iListColors.tpl	(revision 5961)
+++ /extensions/ColorStat/admin/cstat_stat_show_iListColors.tpl	(revision 5961)
@@ -0,0 +1,23 @@
+<table class="littlefont" style="width:100%;" id="iListColorsTable">
+  {foreach from=$datas key=name item=data}
+  <tr>
+
+    <td style="width:40px;background-color:#{$data.color_id};">&nbsp;</td>
+    <td class="colorFont">#{$data.color_id}</td>
+
+    <td width="60px">{$data.num_images}</td>
+    <td width="40px">{$data.pct_images}</td>
+    <td width="110px">
+      <div class="pctBar{$themeconf.name}" style="width:{$data.pct_images}px;"></div>
+    </td>
+
+    <td width="80px">{$data.num_pixels}</td>
+    <td width="40px">{$data.pct_pixels}</td>
+    <td width="110px">
+      <div class="pctBar{$themeconf.name}" style="width:{$data.pct_pixels}px;"></div>
+    </td>
+
+  </tr>
+  {/foreach}
+</table>
+
Index: /extensions/ColorStat/admin/index.php
===================================================================
--- /extensions/ColorStat/admin/index.php	(revision 5961)
+++ /extensions/ColorStat/admin/index.php	(revision 5961)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | 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/ColorStat/admin/plugin_admin.php
===================================================================
--- /extensions/ColorStat/admin/plugin_admin.php	(revision 5961)
+++ /extensions/ColorStat/admin/plugin_admin.php	(revision 5961)
@@ -0,0 +1,41 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : ColorStat
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  --------------------------------------------------------------------------- */
+
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+global $prefixeTable;
+load_language('plugin.lang', CSTAT_PATH);
+
+$main_plugin_object = get_plugin_data($plugin_id);
+
+/*
+ * if the plugin is newly installed, display a special configuration page
+ * otherwise, display normal page
+ */
+
+$config=Array();
+GPCCore::loadConfig('cstat', $config);
+
+if($config['newInstall']=='n')
+{
+  include(CSTAT_PATH."cstat_aip.class.inc.php");
+  $plugin_aip = new CStat_AIP($prefixeTable, $main_plugin_object->getFileLocation());
+}
+else
+{
+  include(CSTAT_PATH."cstat_aip_install.class.inc.php");
+  $plugin_aip = new CStat_AIPInstall($prefixeTable, $main_plugin_object->getFileLocation());
+}
+
+$plugin_aip->manage();
+?>
Index: /extensions/ColorStat/cstat.css
===================================================================
--- /extensions/ColorStat/cstat.css	(revision 5961)
+++ /extensions/ColorStat/cstat.css	(revision 5961)
@@ -0,0 +1,33 @@
+#iLargeColorTable p, #iSmallColorTable p {
+  float:left;
+  margin:0px;
+  padding:0px;
+  padding-bottom:10px;
+}
+
+#iLargeColorTable, #iSmallColorTable {
+  margin-left:30px;
+  padding:10px;
+}
+
+#iSteps fieldset p {
+  text-align:justify;
+  margin:8px;
+  margin-top:0px;
+}
+
+table .colorListSample {
+  border:1px solid #505050;
+}
+
+#iHeaderListColors { width:100%; border:1px solid; border-collapse: collapse; margin-top:3px; }
+#iListColors { width:100%; border:1px solid; height:280px; border-top:0px; overflow:auto; position:relative; left:-1px;}
+#iListColorsTable td { text-align:left; }
+
+#iListColors.roma table tr:hover { background:#303030;  }
+#iListColors.clear table tr:hover {  color: #D54E21; background:#dbe8f3; }
+
+.colorFont {
+  font-family:monospace;
+  font-size:130%;
+}
Index: /extensions/ColorStat/cstat_aim.class.inc.php
===================================================================
--- /extensions/ColorStat/cstat_aim.class.inc.php	(revision 5961)
+++ /extensions/ColorStat/cstat_aim.class.inc.php	(revision 5961)
@@ -0,0 +1,43 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : ColorStat
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.dnsalias.com
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  CSTAT_AIM : classe to manage plugin integration into plugin menu
+
+  --------------------------------------------------------------------------- */
+
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+include_once('cstat_root.class.inc.php');
+
+class CStat_AIM extends CStat_root
+{
+  public function __construct($prefixeTable, $filelocation)
+  {
+    parent::__construct($prefixeTable, $filelocation);
+  }
+
+  /*
+    initialize events call for the plugin
+  */
+  public function initEvents()
+  {
+    parent::initEvents();
+    add_event_handler('get_admin_plugin_menu_links', array(&$this, 'pluginAdminMenu') );
+  }
+
+  /* ---------------------------------------------------------------------------
+  Function needed for plugin activation
+  --------------------------------------------------------------------------- */
+
+} // CStat_AIM class
+
+
+?>
Index: /extensions/ColorStat/cstat_aip.class.inc.php
===================================================================
--- /extensions/ColorStat/cstat_aip.class.inc.php	(revision 5961)
+++ /extensions/ColorStat/cstat_aip.class.inc.php	(revision 5961)
@@ -0,0 +1,705 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : LMT
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  LMT_AIP : classe to manage plugin admin pages
+
+  --------------------------------------------------------------------------- */
+
+include_once('cstat_root.class.inc.php');
+include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/GPCTables.class.inc.php');
+include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
+
+class CStat_AIP extends CStat_root
+{
+  protected $tabsheet;
+
+  public function __construct($prefixeTable, $filelocation)
+  {
+    parent::__construct($prefixeTable, $filelocation);
+    $this->loadConfig();
+    $this->initEvents();
+
+    $this->tabsheet = new tabsheet();
+    $this->tabsheet->add('database',
+                          l10n('cstat_database'),
+                          $this->getAdminLink()."&amp;f_tabsheet=database");
+    $this->tabsheet->add('stat',
+                          l10n('cstat_stat'),
+                          $this->getAdminLink()."&amp;f_tabsheet=stat");
+    $this->tabsheet->add('search',
+                          l10n('cstat_search'),
+                          $this->getAdminLink()."&amp;f_tabsheet=search");
+    $this->tabsheet->add('config',
+                          l10n('cstat_config'),
+                          $this->getAdminLink()."&amp;f_tabsheet=config");
+  }
+
+  public function __destruct()
+  {
+    unset($this->tabsheet);
+    parent::__destruct();
+  }
+
+  /*
+    initialize events call for the plugin
+  */
+  public function initEvents()
+  {
+    parent::initEvents();
+    add_event_handler('loc_end_page_header', array(&$this->css, 'applyCSS'));
+    GPCCss::applyGpcCss();
+  }
+
+  /*
+    display administration page
+  */
+  public function manage()
+  {
+    global $template;
+
+    $this->checkRequest();
+
+    $this->returnAjaxContent();
+
+    $template->set_filename('plugin_admin_content', dirname(__FILE__)."/admin/cstat_admin.tpl");
+
+
+    switch($_REQUEST['f_tabsheet'])
+    {
+      case 'database':
+        $this->displayDatabasePage();
+        break;
+      case 'stat':
+        $this->displayStatPage();
+        break;
+      case 'search':
+        $this->displaySearchPage();
+        break;
+      case 'config':
+        $this->displayConfigPage();
+        break;
+    }
+
+    $this->tabsheet->select($_REQUEST['f_tabsheet']);
+    $this->tabsheet->assign();
+    $selected_tab=$this->tabsheet->get_selected();
+    $template->assign($this->tabsheet->get_titlename(), "[".$selected_tab['caption']."]");
+
+    $template_plugin["CSTAT_VERSION"] = "<i>".$this->getPluginName()."</i> ".l10n('cstat_release').CSTAT_VERSION;
+
+    $template->assign('plugin', $template_plugin);
+    $template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
+  }
+
+
+  /*
+    return ajax content
+  */
+  protected function returnAjaxContent()
+  {
+    global $ajax, $template;
+
+    if(isset($_REQUEST['ajaxfct']))
+    {
+      //$this->debug("AJAXFCT:".$_REQUEST['ajaxfct']);
+      $result="<p class='errors'>An error has occured</p>";
+      switch($_REQUEST['ajaxfct'])
+      {
+        case 'updateDatabaseGetStatus':
+          $result=$this->ajax_cstat_updateDatabaseGetStatus();
+          break;
+        case 'updateDatabaseGetList':
+          $result=$this->ajax_cstat_updateDatabaseGetList($_REQUEST['selectMode'], $_REQUEST['numOfItems']);
+          break;
+        case 'updateDatabaseDoAnalyze':
+          $result=$this->ajax_cstat_updateDatabaseDoAnalyze($_REQUEST['imagesList']);
+          break;
+        case 'updateDatabaseConsolidation':
+          $result=$this->ajax_cstat_updateDatabaseConsolidation();
+          break;
+        case 'showStatsGetListColors':
+          $result=$this->ajax_cstat_showStatsGetListColors($_REQUEST['orderType']);
+          break;
+      }
+      GPCAjax::returnResult($result);
+    }
+  }
+
+  /**
+   * check the $_REQUEST values and set default values
+   *
+   */
+  protected function checkRequest()
+  {
+    if(!isset($_REQUEST['f_tabsheet'])) $_REQUEST['f_tabsheet']='stat';
+
+
+    if(!($_REQUEST['f_tabsheet']=='database' or
+         $_REQUEST['f_tabsheet']=='stat' or
+         $_REQUEST['f_tabsheet']=='search' or
+         $_REQUEST['f_tabsheet']=='config')) $_REQUEST['f_tabsheet']='stat';
+
+
+    if(isset($_REQUEST['ajaxfct']))
+    {
+      if($_REQUEST['ajaxfct']=='updateDatabaseGetList')
+      {
+        if(!isset($_REQUEST['selectMode'])) $_REQUEST['selectMode']='caddieAdd';
+        if(!isset($_REQUEST['numOfItems'])) $_REQUEST['numOfItems']=$this->config['analyze.itemPerRequest'];
+
+        if(!($_REQUEST['selectMode']=='notAnalyzed' or
+             $_REQUEST['selectMode']=='all' or
+             $_REQUEST['selectMode']=='caddieAdd' or
+             $_REQUEST['selectMode']=='caddieReplace')) $_REQUEST['selectMode']='caddieAdd';
+
+        if($_REQUEST['numOfItems'] <=0 or $_REQUEST['numOfItems']>100) $_REQUEST['numOfItems']=10;
+      }
+
+
+      if($_REQUEST['ajaxfct']=='updateDatabaseDoAnalyze')
+      {
+        if(!isset($_REQUEST['imagesList'])) $_REQUEST['imagesList']='';
+      }
+
+      if($_REQUEST['ajaxfct']=='showStatsGetListColors')
+      {
+        if(!isset($_REQUEST['orderType'])) $_REQUEST['orderType']='img';
+
+        if(!($_REQUEST['orderType']=='color' or
+             $_REQUEST['orderType']=='img' or
+             $_REQUEST['orderType']=='pixels')) $_REQUEST['orderType']=='img';
+      }
+
+    }
+
+  }
+
+  /**
+   * display the database page
+   */
+  protected function displayDatabasePage()
+  {
+    global $template;
+
+    $template->set_filename('body_page',
+                dirname($this->getFileLocation()).'/admin/cstat_database.tpl');
+
+    $datas=Array(
+      'urlRequest' => $this->getAdminLink(),
+      'numberOfItemsPerRequest' => $this->config['analyze.itemPerRequest']
+    );
+    $template->assign('datas', $datas);
+    $template->assign_var_from_handle('CSTAT_BODY_PAGE', 'body_page');
+  } //displayDatabasePage
+
+  /**
+   * display the stat page
+   */
+  protected function displayStatPage()
+  {
+    global $template;
+
+    $template->set_filename('body_page',
+                dirname($this->getFileLocation()).'/admin/cstat_stat.tpl');
+
+    $generalStats=$this->getGeneralStats();
+
+    $colors=Array();
+    $sql="SELECT color_id, num_images, num_pixels
+          FROM ".$this->tables['color_table']."
+          WHERE num_images > 0
+          ORDER BY color_id ";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=pwg_db_fetch_assoc($result))
+      {
+        $colors[$row['color_id']]=Array('num_images' => $row['num_images'], 'num_pixels' => $row['num_pixels']);
+      }
+    }
+
+    $colorTable=ColorStat::getColorTable(
+      $this->colorTableSize[$this->config['analyze.colorTable']][0],
+      $this->colorTableSize[$this->config['analyze.colorTable']][1]
+    );
+    foreach($colorTable as $key=>$val)
+    {
+      foreach($val as $key2=>$val2)
+      {
+        $rgb=$val2->getRGB()->getHexString();
+        $colorTable[$key][$key2]=Array(
+          'color' => $rgb,
+          'pct'   => (array_key_exists($rgb, $colors))?sprintf("%.2f", round(100*$colors[$rgb]['num_pixels']/$generalStats['pixelsAnalyzedSum'],2)):"",
+          'num'   => (array_key_exists($rgb, $colors))?$colors[$rgb]['num_images']:"",
+        );
+      }
+    }
+
+    $datas=Array(
+      'colorTable' => $this->htmlColorTable(
+                        $colorTable,
+                        ($this->config['analyze.colorTable']=='small')?19:10
+                      ),
+      'urlRequest' => $this->getAdminLink(),
+      'config_GetListColors_OrderType' => $this->config['display.stat.orderType'],
+    );
+    $template->assign('datas', $datas);
+    $template->assign_var_from_handle('CSTAT_BODY_PAGE', 'body_page');
+  } //displayStatPage
+
+
+  /**
+   * display search page
+   */
+  protected function displaySearchPage()
+  {
+    global $template, $lang;
+
+    $template->set_filename('body_page',
+                dirname($this->getFileLocation()).'/admin/cstat_search.tpl');
+
+    $template->assign_var_from_handle('CSTAT_BODY_PAGE', 'body_page');
+  } //displaySearchPage
+
+
+  /**
+   * manage display of config page & save config
+   */
+  protected function displayConfigPage()
+  {
+    /*
+    if(!$this->adviser_abort())
+    {
+      if(isset($_POST['submit_save_config']))
+      {
+        foreach($this->config as $key => $val)
+        {
+          if(is_array($val))
+          {
+            foreach($languages as $key2 => $val2)
+            {
+              if(isset($_REQUEST[str2url('f_'.$key.'_'.$key2)]))
+              {
+                $this->config[$key][$key2] = htmlspecialchars(stripslashes($_REQUEST[str2url('f_'.$key.'_'.$key2)]), ENT_QUOTES);
+              }
+            }
+          }
+          else
+          {
+            if(isset($_REQUEST['f_'.$key]))
+            {
+              $this->config[$key] = $_REQUEST['f_'.$key];
+            }
+          }
+
+        }
+        $this->displayResult(l10n('lmt_save_config'), $this->saveConfig());
+      }
+    }*/
+    $this->displayConfig();
+  }
+
+  /**
+   * display config page
+   */
+  protected function displayConfig()
+  {
+    global $template, $lang;
+
+    $template->set_filename('body_page',
+                dirname($this->getFileLocation()).'/admin/cstat_config.tpl');
+
+    $template->assign_var_from_handle('CSTAT_BODY_PAGE', 'body_page');
+  } //displayConfig
+
+
+  /**
+   * manage adviser profile
+   * return true if user is adviser
+   */
+  protected function adviser_abort()
+  {
+    if(is_adviser())
+    {
+      $this->displayResult(l10n("cstat_adviser_not_allowed"), false);
+      return(true);
+    }
+    return(false);
+  }
+
+
+  /* ---------------------------------------------------------------------------
+    function to manage database manipulation
+  --------------------------------------------------------------------------- */
+  protected function analyzeImageFile($fileName, $imageId, $colorTable)
+  {
+    // set the picture to the 'try to analyze' statut
+    $sql="UPDATE ".$this->tables['images']." SET analyzed='t'
+          WHERE image_id=".$imageId.";";
+    pwg_query($sql);
+
+    $colors=ColorStat::getFileColors(
+      $fileName,
+      $colorTable,
+      Array(
+        'quality' => 8,
+        'numColors' => 16,
+        'maxTime' => $this->config['analyze.maxTime'],
+        'pps' => $this->config['analyze.pps'],
+      )
+    );
+
+    if($colors!==false and
+       ColorStat::$fileColorsStat['colors']>0 and
+       ColorStat::$fileColorsStat['analyzed']>0)
+    {
+      $sql="UPDATE ".$this->tables['images']."
+              SET analyzed='y',
+                  num_colors='".ColorStat::$fileColorsStat['colors']."',
+                  num_pixels='".ColorStat::$fileColorsStat['pixels']."',
+                  analyzed_pixels='".ColorStat::$fileColorsStat['analyzed']."',
+                  pps='".ColorStat::$fileColorsStat['pps']."',
+                  time='".ColorStat::$fileColorsStat['time']."',
+                  quality='".ColorStat::$fileColorsStat['quality']."'
+            WHERE image_id=".$imageId.";";
+      pwg_query($sql);
+      $sql="";
+      foreach($colors as $key=>$val)
+      {
+        /*
+         * $key => RGB color #RRGGBB
+         * $val => Array (
+         *            'hsv' => Array ('H', 'S', 'V')
+         *            'num' => integer
+         *            'pct' => float
+         *          )
+         */
+
+        $sql.=(($sql=="")?"":", ")."
+              ('".$imageId."', '".$key."', ".$val['pct'].", ".$val['num'].")";
+      }
+      $sql="REPLACE INTO ".$this->tables['images_colors']."
+                VALUES ".$sql;
+      pwg_query($sql);
+
+      return($imageId.'='.ColorStat::$fileColorsStat['colors'].';');
+    }
+    else
+    {
+      return($imageId.'=KO;');
+    }
+  }
+
+
+  protected function getGeneralStats()
+  {
+    $returned=Array(
+      'nbImages' => 0,
+      'totalTime' => 0,
+      'pixelsAnalyzedMax' => 0,
+      'pixelsAnalyzedMin' => 0,
+      'pixelsAnalyzedAvg' => 0,
+      'pixelsAnalyzedSum' => 0,
+      'totalPixels' => 0,
+      'ppsMax' => 0,
+      'ppsMin' => 0,
+      'ppsAvg' => 0,
+      'qualityMax' => 0,
+      'qualityMin' => 0,
+      'qualityAvg' => 0,
+    );
+    $sql="SELECT COUNT(image_id) AS nbImages,
+                 SUM(time) AS totalTime,
+                 MAX(analyzed_pixels) AS pixelsAnalyzedMax,
+                 MIN(analyzed_pixels) AS pixelsAnalyzedMin,
+                 AVG(analyzed_pixels) AS pixelsAnalyzedAvg,
+                 SUM(analyzed_pixels) AS pixelsAnalyzedSum,
+                 SUM(num_pixels) AS totalPixels,
+                 MAX(pps) AS ppsMax,
+                 MIN(pps) AS ppsMin,
+                 AVG(pps) AS ppsAvg,
+                 MAX(quality) AS qualityMax,
+                 MIN(quality) AS qualityMin,
+                 AVG(quality) AS qualityAvg
+          FROM ".$this->tables['images']."
+          WHERE analyzed='y';";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=pwg_db_fetch_assoc($result))
+      {
+        $returned=$row;
+      }
+    }
+    return($returned);
+  }
+
+  /* ---------------------------------------------------------------------------
+    ajax functions
+  --------------------------------------------------------------------------- */
+
+  /**
+   * returns a list of formated string, separated with a semi-colon :
+   *  - number of current analyzed pictures
+   *  - number of pictures not analyzed + number of picture in error
+   *
+   * @return String
+   */
+  private function ajax_cstat_updateDatabaseGetStatus()
+  {
+    $numOfPictures=0;
+    $numOfPicturesNotAnalyzed=0;
+    $numOfPicturesInError=0;
+
+    $sql="SELECT COUNT(image_id), analyzed FROM ".$this->tables['images']."
+            GROUP BY analyzed;";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=pwg_db_fetch_row($result))
+      {
+        switch($row[1])
+        {
+          case 'n': //no
+            $numOfPicturesNotAnalyzed=$row[0];
+            break;
+          case 'y': //yes
+            $numOfPictures=$row[0];
+            break;
+          case 't': //tried to be analyzed, but not finished
+            $numOfPicturesInError=$row[0];
+            break;
+        }
+      }
+    }
+
+    return(sprintf(l10n("cstat_numberOfAnalyzedPictures"), $numOfPictures).";".
+           sprintf(l10n("cstat_numberOfNotAnalyzedPictures"), $numOfPicturesNotAnalyzed).";".
+           sprintf(l10n("cstat_numberOfPicturesInError"), $numOfPicturesInError));
+  }
+
+
+  /**
+   * return a list of picture Id
+   *
+   * picture id are separated with a space " "
+   * picture id are grouped in blocks of 'NumberOfItemsPerRequest' items and
+   * are separated with a semi-colon ";"
+   *
+   * client side just have to split blocks, and transmit it to the server
+   *
+   * There is four mode to determine the pictures being analyzed :
+   *  - "all"           : analyze all the images (add & replace)
+   *  - "notAnalyzed"   : analyze only the images not yet analyzed (add)
+   *  - "caddieAdd"     : analyze all the images of the caddie (add)
+   *  - "caddieReplace" : analyze all the images of the caddie (add & replace)
+   *
+   * @param String $mode
+   * @param Integer $nbOfItems : number of items per request
+   * @return String : list of image id to be analyzed, separated with a space
+   *                      "23 78 4523 5670"
+   */
+  private function ajax_cstat_updateDatabaseGetList($mode, $nbOfItems)
+  {
+    global $user;
+
+    $returned="";
+
+    $sql="SELECT cit.image_id FROM ".$this->tables['images']." cit";
+    if($mode=="notAnalyzed")
+    {
+      $sql.=" WHERE cit.analyzed='n'";
+    }
+    elseif($mode=="caddieAdd" or $mode=="caddieReplace")
+    {
+
+      $sql.=" LEFT JOIN ".CADDIE_TABLE." ct ON cit.image_id = ct.element_id
+            WHERE ct.user_id = ".$user['id']." ";
+      if($mode=="caddieAdd") $sql.=" AND cit.analyzed='n'";
+    }
+
+    if($mode=="all" or $mode=="caddieReplace")
+    {
+      pwg_query("UPDATE ".$this->tables['images']."
+                  SET analyzed='n',
+                      num_colors=0,
+                      num_pixels=0,
+                      analyzed_pixels=0,
+                      pps=0,
+                      time=0,
+                      quality=0
+                  WHERE analyzed<>'t'");
+      pwg_query("DELETE FROM ".$this->tables['images_colors']);
+      pwg_query("UPDATE ".$this->tables['color_table']."
+                 SET num_pixels=0, num_images=0;");
+    }
+
+    $result=pwg_query($sql);
+    if($result)
+    {
+      $i=0;
+      while($row=pwg_db_fetch_row($result))
+      {
+        $returned.=$row[0];
+        $i++;
+        if($i>=$nbOfItems)
+        {
+          $returned.=";";
+          $i=0;
+        }
+        else
+        {
+          $returned.=" ";
+        }
+      }
+    }
+    return(trim($returned).";");
+  }
+
+
+
+  /**
+   * extract metadata from images
+   *
+   * @param String $imageList : list of image id to be analyzed, separated with
+   *                            a space
+   *                                "23 78 4523 5670"
+   * @return String : list of the analyzed pictures, with number of colors found
+   *                  for each picture
+   *                    "23=0;78=66;4523=33;5670=91;"
+   */
+  private function ajax_cstat_updateDatabaseDoAnalyze($imagesList)
+  {
+    $list=explode(" ", trim($imagesList));
+
+    $returned="";
+
+    if(count($list)>0 and trim($imagesList)!='')
+    {
+      // $path = path of piwigo's on the server filesystem
+      $path=dirname(dirname(dirname(__FILE__)));
+
+      $sql="SELECT id, path FROM ".IMAGES_TABLE." WHERE id IN (".implode(", ", $list).")";
+      $result=pwg_query($sql);
+      if($result)
+      {
+        $colorTable=ColorStat::getColorTable(
+          $this->colorTableSize[$this->config['analyze.colorTable']][0],
+          $this->colorTableSize[$this->config['analyze.colorTable']][1]
+        );
+
+        while($row=pwg_db_fetch_assoc($result))
+        {
+          /*
+           * in some case (in a combination of some pictures), when there is too
+           * much pictures to analyze in the same request, a fatal error occurs
+           * with the message : "Allowed memory size of XXXXX bytes exhausted"
+           *
+           *
+           * tracking memory leak is not easy... :-(
+           *
+           */
+          //echo "analyzing:".$row['id']."\n";
+          //$mem1=memory_get_usage();
+          //echo "memory before analyze:".$mem1."\n";
+          $returned.=$this->analyzeImageFile($path."/".$row['path'], $row['id'], $colorTable);
+          //echo $returned."\n";
+          //$mem2=memory_get_usage();
+          //echo "memory after analyze:".$mem2." (".($mem2-$mem1).")\n";
+        }
+      }
+    }
+    return($returned);
+  }
+
+
+  /**
+   * make consolidation for the color_table :
+   *  - count number of images using a color
+   *  - count number of pixels of a color
+   */
+  private function ajax_cstat_updateDatabaseConsolidation()
+  {
+    $sql="UPDATE ".$this->tables['color_table']." cct,
+                 (SELECT color_id,
+                         count(image_id) AS num_images,
+                         sum(num_pixels) AS num_pixels
+                  FROM ".$this->tables['images_colors']."
+                  GROUP BY color_id) cic
+          SET cct.num_images=cic.num_images,
+              cct.num_pixels=cic.num_pixels
+          WHERE cct.color_id=cic.color_id;";
+    pwg_query($sql);
+    return("ok");
+  }
+
+
+
+  /**
+   * return a formatted <table> (using the template "cstat_stat_show_iListColors")
+   * of used tag with, for each tag, the number and the percentage of pictures
+   * where the tag was found
+   *
+   * @param String $orderType : order for the list (by color 'color' or by number
+   *                            of pictures 'img' or by number of pixels 'pixels')
+   * @return String
+   */
+  private function ajax_cstat_showStatsGetListColors($orderType)
+  {
+    global $template;
+
+    $this->config['display.stat.orderType'] = $orderType;
+    $this->saveConfig();
+
+    $local_tpl = new Template(AMD_PATH."admin/", "");
+    $local_tpl->set_filename('body_page',
+                  dirname($this->getFileLocation()).'/admin/cstat_stat_show_iListColors.tpl');
+
+    $generalStats=$this->getGeneralStats();
+
+    $sql="SELECT color_id, num_images, num_pixels
+          FROM ".$this->tables['color_table']."
+          WHERE num_images > 0 ";
+    if($orderType=='color')
+    {
+      $sql.=" ORDER BY hue ASC, saturation ASC, value DESC";
+    }
+    elseif($orderType=='img')
+    {
+      $sql.=" ORDER BY num_images DESC, num_pixels DESC ";
+    }
+    elseif($orderType=='pixels')
+    {
+      $sql.=" ORDER BY num_pixels DESC, num_images DESC ";
+    }
+
+    $datas=Array();
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=pwg_db_fetch_assoc($result))
+      {
+        $row['pct_images']=sprintf('%.2f', round(100*$row['num_images']/$generalStats['nbImages'],2));
+        $row['pct_pixels']=sprintf('%.2f', round(100*$row['num_pixels']/$generalStats['pixelsAnalyzedSum'],2));
+        $datas[]=$row;
+      }
+    }
+
+    $local_tpl->assign('themeconf', Array('name' => $template->get_themeconf('name')));
+    $local_tpl->assign('datas', $datas);
+
+    return($local_tpl->parse('body_page', true));
+  }
+
+} //class
+
+
+?>
Index: /extensions/ColorStat/cstat_aip_install.class.inc.php
===================================================================
--- /extensions/ColorStat/cstat_aip_install.class.inc.php	(revision 5961)
+++ /extensions/ColorStat/cstat_aip_install.class.inc.php	(revision 5961)
@@ -0,0 +1,230 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : ColorStat
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  LMT_AIP : classe to manage plugin admin pages
+
+  --------------------------------------------------------------------------- */
+
+include_once('cstat_root.class.inc.php');
+include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/GPCTables.class.inc.php');
+include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
+
+class CStat_AIPInstall extends CStat_root
+{
+  protected $tabsheet;
+
+  public function __construct($prefixeTable, $filelocation)
+  {
+    parent::__construct($prefixeTable, $filelocation);
+    $this->loadConfig();
+    $this->initEvents();
+
+    $this->tabsheet = new tabsheet();
+    $this->tabsheet->add('install',
+                          l10n('cstat_install'),
+                          $this->getAdminLink()."&amp;f_tabsheet=install");
+  }
+
+  public function __destruct()
+  {
+    unset($this->tabsheet);
+    parent::__destruct();
+  }
+
+  /*
+    initialize events call for the plugin
+  */
+  public function initEvents()
+  {
+    parent::initEvents();
+    add_event_handler('loc_end_page_header', array(&$this->css, 'applyCSS'));
+  }
+
+  /*
+    display administration page
+  */
+  public function manage()
+  {
+    global $template;
+
+    $this->checkRequest();
+    $this->returnAjaxContent();
+
+    $template->set_filename('plugin_admin_content', dirname($this->getFileLocation())."/admin/cstat_admin.tpl");
+
+    $this->displayInstallPage();
+
+    $this->tabsheet->select($_REQUEST['f_tabsheet']);
+    $this->tabsheet->assign();
+    $selected_tab=$this->tabsheet->get_selected();
+    $template->assign($this->tabsheet->get_titlename(), "[".$selected_tab['caption']."]");
+
+    $template_plugin["CSTAT_VERSION"] = "<i>".$this->getPluginName()."</i> ".l10n('cstat_release').CSTAT_VERSION;
+
+    $template->assign('plugin', $template_plugin);
+    $template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
+  }
+
+
+  /*
+    return ajax content
+  */
+  protected function returnAjaxContent()
+  {
+    global $ajax, $template;
+
+    if(isset($_REQUEST['ajaxfct']))
+    {
+      //$this->debug("AJAXFCT:".$_REQUEST['ajaxfct']);
+      $result="<p class='errors'>An error has occured</p>";
+      switch($_REQUEST['ajaxfct'])
+      {
+        case 'installProcess':
+          $result=$this->ajax_installProcess($_REQUEST['tableSize']);
+          break;
+      }
+      GPCAjax::returnResult($result);
+    }
+  }
+
+  /**
+   * check the $_REQUEST values and set default values
+   *
+   */
+  protected function checkRequest()
+  {
+    $_REQUEST['f_tabsheet']='install';
+
+    if(isset($_REQUEST['ajaxfct']))
+    {
+      if($_REQUEST['ajaxfct']=='installProcess')
+      {
+        if(!isset($_REQUEST['tableSize'])) $_REQUEST['tableSize']='small';
+      }
+    }
+  }
+
+
+  /**
+   * display config page
+   */
+  protected function displayInstallPage()
+  {
+    global $template, $lang;
+
+
+
+    $template->set_filename('body_page',
+                dirname($this->getFileLocation()).'/admin/cstat_install_page.tpl');
+
+    $smallColorTable=ColorStat::getColorTable($this->colorTableSize['small'][0],$this->colorTableSize['small'][1]);
+    $largeColorTable=ColorStat::getColorTable($this->colorTableSize['large'][0],$this->colorTableSize['large'][1]);
+    $template->assign('smallTableColor', $this->htmlColorTable($smallColorTable, 19));
+    $template->assign('largeTableColor', $this->htmlColorTable($largeColorTable, 10));
+
+    $template->assign(
+      'smallColorList1',
+      $this->htmlColorList(
+        ColorStat::getFileColors(dirname($this->getFileLocation()).'/image/sample1.png', $smallColorTable, Array('quality' => 8, 'numColors' => 16)),
+        16, 18, '', 'colorListSample'
+      )
+    );
+    $pps=ColorStat::$fileColorsStat['pps'];
+
+    $template->assign(
+      'largeColorList1',
+      $this->htmlColorList(
+        ColorStat::getFileColors(dirname($this->getFileLocation()).'/image/sample1.png', $largeColorTable, Array('quality' => 8, 'numColors' => 16)),
+        16, 18, '', 'colorListSample'
+      )
+    );
+    $pps+=ColorStat::$fileColorsStat['pps'];
+
+    $template->assign(
+      'smallColorList2',
+      $this->htmlColorList(
+        ColorStat::getFileColors(dirname($this->getFileLocation()).'/image/sample2.png', $smallColorTable, Array('quality' => 8, 'numColors' => 16)),
+        16, 18, '', 'colorListSample'
+      )
+    );
+    $pps+=ColorStat::$fileColorsStat['pps'];
+
+    $template->assign(
+      'largeColorList2',
+      $this->htmlColorList(
+        ColorStat::getFileColors(dirname($this->getFileLocation()).'/image/sample2.png', $largeColorTable, Array('quality' => 8, 'numColors' => 16)),
+        16, 18, '', 'colorListSample'
+      )
+    );
+    $pps+=ColorStat::$fileColorsStat['pps'];
+
+    unset($smallColorTable);
+    unset($largeColorTable);
+
+    $this->config['analyze.pps']=round($pps/4,0);
+    $this->saveConfig();
+
+    $template->assign('urlRequest', $this->getAdminLink());
+    $template->assign('help',
+      Array(
+        'SmallColorTable' => GPCCore::BBtoHTML(l10n('cstat_help_small_color_table')),
+        'LargeColorTable' => GPCCore::BBtoHTML(l10n('cstat_help_large_color_table')),
+        'Step1' => GPCCore::BBtoHTML(l10n('cstat_step_1_help')),
+
+      )
+    );
+
+
+
+    $template->assign_var_from_handle('CSTAT_BODY_PAGE', 'body_page');
+  } //displayInstallPage
+
+
+
+
+  /* ---------------------------------------------------------------------------
+    function to manage database manipulation
+  --------------------------------------------------------------------------- */
+
+
+  /* ---------------------------------------------------------------------------
+    ajax functions
+  --------------------------------------------------------------------------- */
+  protected function ajax_installProcess($tableSize)
+  {
+    $this->config['newInstall']='n';
+    $this->config['analyze.colorTable']=$tableSize;
+    $this->saveConfig();
+
+    $colorTable=ColorStat::getColorTable($this->colorTableSize[$tableSize][0],$this->colorTableSize[$tableSize][1]);
+
+    foreach($colorTable as $key => $val)
+    {
+      foreach($val as $key2 => $val2)
+      {
+        $hsv=$val2->get();
+        $sql.=(($sql=="")?"":", ")."('".$val2->getRGB()->getHexString()."',
+               '".$hsv['H']."',
+               '".$hsv['S']."',
+               '".$hsv['V']."',
+               0, 0)";
+      }
+    }
+    $sql="REPLACE INTO ".$this->tables['color_table']."
+              VALUES ".$sql;
+    pwg_query($sql);
+    return("OK");
+  }
+
+} //class
+
+
+?>
Index: /extensions/ColorStat/cstat_colorstat.class.inc.php
===================================================================
--- /extensions/ColorStat/cstat_colorstat.class.inc.php	(revision 5961)
+++ /extensions/ColorStat/cstat_colorstat.class.inc.php	(revision 5961)
@@ -0,0 +1,704 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : ColorStat
+  Author     : Grum
+    email    : grum@grum.fr
+    website  : http://photos.grum.fr
+    PWG user : http://forum.piwigo.org/profile.php?id=3706
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  Provided classes :
+  * RGB
+    public functions :
+      __construct($R, $G, $B)
+      set($R, $G, $B)
+      setInt($value)
+      get($floatValue=false)
+      getHexString()
+      getInt()
+      getHSV()
+      setHSV(HSV $hsv)
+    private functions :
+      setProperty($property, $value)
+
+  * HSV
+    public functions :
+      __construct($H, $S, $V)
+      set($H, $S, $V)
+      get()
+      getRGB()
+      setRGB(RGB $rgb)
+    private functions :
+      setProperty($property, $value)
+
+  * ColorStat
+    public functions :
+    static getFileColors($fileName, $colorTable, $quality=1)
+    static RGBtoHSV(RGB $RGB)
+    static HSVtoRGB(HSV $HSV)
+    static IntToRGB($rgb)
+    static getColorTable($huePrec=10, $prec=10, $returnedType='HSV')
+    static getColorFromTable(HSV $hsvObject, $colorTable)
+
+  --------------------------------------------------------------------------- */
+
+/**
+ * The RGB class allows to read & write a RGB value
+ */
+class RGB {
+  protected $RGB = Array('R' => 0, 'G' => 0, 'B' => 0);
+
+  public function __construct($R=0, $G=0, $B=0)
+  {
+    $this->set($R, $G, $B);
+  }
+
+  public function set($R, $G, $B)
+  {
+    $this->setProperty('R', $R);
+    $this->setProperty('G', $G);
+    $this->setProperty('B', $B);
+    return($this->get());
+  }
+
+  public function setInt($value)
+  {
+    $tmp=ColorStat::IntToRGB($value);
+    $tmp2=$tmp->get();
+    $this->set($tmp2['R'], $tmp2['G'], $tmp2['B']);
+    unset($tmp2);
+    unset($tmp);
+  }
+
+  public function get($floatValue=false)
+  {
+    if($floatValue)
+    {
+      return(
+        Array(
+          'R' => $this->RGB['R']/255,
+          'G' => $this->RGB['G']/255,
+          'B' => $this->RGB['B']/255,
+        )
+      );
+    }
+    else
+    {
+      return($this->RGB);
+    }
+  }
+
+  public function getHexString()
+  {
+    return(sprintf('%02x%02x%02x', $this->RGB['R'], $this->RGB['G'], $this->RGB['B']));
+  }
+
+  public function getInt()
+  {
+    return(  $this->RGB['R']<<16 + $this->RGB['G']<<8 + $this->RGB['B']);
+  }
+
+  public function getHSV()
+  {
+    return(ColorStat::RGBtoHSV($this));
+  }
+
+  public function setHSV(HSV $hsv)
+  {
+    $tmp=ColorStat::HSVtoRGB($hsv);
+    $tmp2=$tmp->get();
+    $this->set($tmp2['R'], $tmp2['G'], $tmp2['B']);
+    unset($tmp2);
+    unset($tmp);
+  }
+
+  private function setProperty($property, $value)
+  {
+    if($property=='R' or $property=='G' or $property=='B')
+    {
+      if($value<0) $value=0;
+      if($value>255) $value=255;
+
+      $this->RGB[$property]=$value;
+      return($this->RGB[$property]);
+    }
+  }
+}
+
+
+/**
+ * The HSV class allows to read & write a HSV value
+ */
+class HSV {
+  protected $HSV = Array('H' => 0, 'S' => 0, 'V' => 0);
+
+  public function __construct($H=0, $S=0, $V=0)
+  {
+    $this->set($H, $S, $V);
+  }
+
+  public function set($H, $S, $V)
+  {
+    $this->setProperty('H', $H);
+    $this->setProperty('S', $S);
+    $this->setProperty('V', $V);
+    return($this->get());
+  }
+
+  public function get()
+  {
+    return($this->HSV);
+  }
+
+  public function getRGB()
+  {
+    return(ColorStat::HSVtoRGB($this));
+  }
+
+  public function setRGB(RGB $rgb)
+  {
+    $tmp=ColorStat::RGBtoHSV($rgb);
+    $tmp2=$tmp->get();
+    $this->set($tmp2['H'], $tmp2['S'], $tmp2['V']);
+    unset($tmp2);
+    unset($tmp);
+  }
+
+  private function setProperty($property, $value)
+  {
+    if($property=='H')
+    {
+      $this->HSV['H']=$value%360;
+      return($this->HSV['H']);
+    }
+    elseif($property=='S' or $property=='V')
+    {
+      if($value<0) $value=0;
+      if($value>100) $value=100;
+
+      $this->HSV[$property]=$value;
+      return($this->HSV[$property]);
+    }
+    return(false);
+  }
+}
+
+
+
+
+class ColorStat {
+  static public $fileColorsStat = Array(
+    'pixels' => 0,
+    'analyzed' => 0,
+    'time' => 0,
+    'colors' =>0,
+    'fileName' => "",
+    'quality' => 0,
+  );
+
+  /**
+   *
+   * @param String $fileName : the name of picture to scan
+   * @param String $colorTable : the color table model
+   * @param String $options : Array of options
+   *                            'quality' : set the quality for analyze
+   *                            'maxTime' : set the maximum time for analyze
+   *                            'pps'     : pixel per second analyzed
+   *                          if 'maxTime' and 'pps' are greater than zero, the
+   *                          quality parameter is computed automatically
+   * @return Array : an array of HSV objects
+   */
+  static function getFileColors($fileName, $colorTable, $options=array())
+  {
+    $options=self::checkOptions($options);
+
+    self::$fileColorsStat=Array(
+      'pixels'   => 0,
+      'analyzed' => 0,
+      'time' => 0,
+      'pps' =>0,
+    );
+
+    if(file_exists($fileName))
+    {
+      $time=microtime(true);
+
+      if(preg_match('/.*\.gif$/i', $fileName))
+      {
+        $image = imagecreatefromgif($fileName);
+      }
+      elseif(preg_match('/.*\.(jpg|jpeg)$/i', $fileName))
+      {
+        $image = imagecreatefromjpeg($fileName);
+      }
+      elseif(preg_match('/.*\.png$/i', $fileName))
+      {
+        $image = imagecreatefrompng($fileName);
+      }
+      else
+      {
+        return(-2);
+      }
+
+      $imageWidth=imagesx($image);
+      $imageHeight=imagesy($image);
+
+      if($options['pps']>0 && $options['maxTime']>0)
+      {
+        $quality=round(sqrt($imageWidth*$imageHeight/($options['pps']*$options['maxTime'])), 0);
+      }
+      else
+      {
+        $quality=$options['quality'];
+      }
+
+      $imageWorkWidth=round($imageWidth/$quality,0);
+      $imageWorkHeight=round($imageHeight/$quality,0);
+      $imageWork=imagecreatetruecolor($imageWorkWidth,$imageWorkHeight);
+      imagecopyresampled($imageWork, $image, 0, 0, 0, 0, $imageWorkWidth, $imageWorkHeight, $imageWidth, $imageHeight);
+      //imagecopyresized($imageWork, $image, 0, 0, 0, 0, $imageWorkWidth, $imageWorkHeight, $imageWidth, $imageHeight);
+      imagedestroy($image);
+
+      $returned=Array();
+
+      $i=0;
+      for($px=0;$px<$imageWorkWidth;$px++)
+      {
+        for($py=0;$py<$imageWorkHeight;$py++)
+        {
+          $i++;
+          $value=imagecolorat($imageWork, $px, $py);
+
+          $rgb=self::IntToRGB($value);
+          //echo sprintf("%06x", $value)." => ".$rgb->getHexString();
+
+          $color=self::getColorFromTable($rgb->getHSV(), $colorTable)->getHexString();
+          //echo " ($i) $color<br>";
+
+          if(array_key_exists($color, $returned))
+          {
+            $returned[$color]['num']=$returned[$color]['num']+1;
+          }
+          else
+          {
+            $returned[$color]=Array(
+              'hsv' => $rgb->getHSV()->get(),
+              'num' => 1,
+              'pct' => 0,
+            );
+          }
+          unset($rgb);
+        }
+      }
+
+      /*
+      $fName="q".$quality."_c".$options['numColors']."_".$fileName.".png";
+      imagepng($imageWork, $fName);
+      */
+
+      imagedestroy($imageWork);
+      uasort($returned, Array('ColorStat', 'sortTones'));
+
+      if($options['numColors']>0)
+      {
+        foreach($returned as $key=>$val)
+        {
+          $returnedColors[$key]=$val;
+          $options['numColors']--;
+          if($options['numColors']<=0) break;
+        }
+      }
+      else
+      {
+        $returnedColors=$returned;
+      }
+
+      self::$fileColorsStat=Array(
+        'pixels'   => $imageWidth*$imageHeight,
+        'analyzed' => $i,
+        'time'     => microtime(true)-$time,
+        'colors'   => count($returned),
+        'pps'      => $i/(microtime(true)-$time),
+        'quality'  => $quality,
+        //'fileName' => $fName,
+      );
+
+      unset($returned);
+
+      foreach($returnedColors as $key => $val)
+      {
+        $returnedColors[$key]['pct']=round(100*$val['num']/self::$fileColorsStat['analyzed'],2);
+      }
+
+      return($returnedColors);
+    }
+    else
+    {
+      return(-1);
+    }
+  }
+
+  /**
+   *  Calculate the HSV value from a RGB value
+   *
+   * @param RGB $RGB : RGB object
+   * @return HSV : new HSV object
+   */
+  static public function RGBtoHSV(RGB $RGB)
+  {
+    $rgbValues=$RGB->get(true);
+    $max=self::max($rgbValues);
+    $min=self::min($rgbValues);
+
+    if($max['value']==$min['value'])
+    {
+      $H=0;
+    }
+    elseif($max['key']=='R')
+    {
+      $H=(60*($rgbValues['G']-$rgbValues['B'])/($max['value']-$min['value'])+360)%360;
+    }
+    elseif($max['key']=='G')
+    {
+      $H=(60*($rgbValues['B']-$rgbValues['R'])/($max['value']-$min['value'])+120);
+    }
+    elseif($max['key']=='B')
+    {
+      $H=(60*($rgbValues['R']-$rgbValues['G'])/($max['value']-$min['value'])+240);
+    }
+
+    $S=round(100*(($max['value']==0)?0:1-$min['value']/$max['value']),0);
+    $V=round(100*$max['value'],0);
+
+    return(new HSV($H, $S, $V));
+  }
+
+  /**
+   *  Calculate the RGB value from a HSV value
+   *
+   * @param HSV $HSV : HSV object
+   * @return RGB : new RGB object
+   */
+  static public function HSVtoRGB(HSV $HSV)
+  {
+    $hsvValues=$HSV->get();
+
+    $h=abs($hsvValues['H']/60)%6;
+    $f=$hsvValues['H']/60-$h;
+    $l=round(2.55*$hsvValues['V']*(1-$hsvValues['S']/100),0);
+    $m=round(2.55*$hsvValues['V']*(1-$f*$hsvValues['S']/100),0);
+    $n=round(2.55*$hsvValues['V']*(1-(1-$f)*$hsvValues['S']/100),0);
+
+    $v=round(2.55*$hsvValues['V'],0);
+
+    switch($h)
+    {
+      case 0:
+        return(new RGB($v, $n, $l));
+        break;
+      case 1:
+        return(new RGB($m, $v, $l));
+        break;
+      case 2:
+        return(new RGB($l, $v, $n));
+        break;
+      case 3:
+        return(new RGB($l, $m, $v));
+        break;
+      case 4:
+        return(new RGB($n, $l, $v));
+        break;
+      case 5:
+        return(new RGB($v, $l, $m));
+        break;
+    }
+  }
+
+  /**
+   *
+   * @param Int $rgb : an integer &hRRGGBB
+   * @return RGB : a RGB object
+   */
+  static public function IntToRGB($rgb)
+  {
+    return(new RGB(($rgb >> 16) & 0xFF, ($rgb >> 8) & 0xFF, $rgb & 0xFF, true));
+  }
+
+  /**
+   * return a color table
+   *  $table = Array(
+   *              Array(),
+   *              Array(),
+   *              ...
+   *              Array(),
+   *              Array(),
+   *           )
+   *  $table[n]    => Array of all colors for a given hue value
+   *  $table[n][m] => HSV object or a color string RRGGBB
+   *
+   *
+   * @param Int $huePrec : degree of precision for hue [1..360]
+   * @param Float $prec    : precision step for saturation & value [1..100]
+   * @param String $returnedType : 'HSV'   => return a HSV object
+   *                               'color' => return a color string RRGGBB
+   * @return Array : the color table
+   */
+  static public function getColorTable($huePrec=10, $prec=10, $returnedType='HSV')
+  {
+    $returned=Array();
+    for($hue=0;$hue<=360;$hue+=$huePrec)
+    {
+      $hueValues=Array();
+
+      $saturation=100;
+      for($value=0;$value<100;$value=$value+=$prec)
+      {
+        $hsv=new HSV($hue, $saturation, $value);
+        if($returnedType=='HSV')
+        {
+          $hueValues[]=$hsv;
+        }
+        else
+        {
+          $hueValues[]=$hsv->getRGB()->getHexString();
+        }
+        unset($hsv);
+      }
+
+      $value=100;
+      for($saturation=100;$saturation>=0;$saturation-=$prec)
+      {
+        $hsv=new HSV($hue, $saturation, $value);
+        if($returnedType=='HSV')
+        {
+          $hueValues[]=$hsv;
+        }
+        else
+        {
+          $hueValues[]=$hsv->getRGB()->getHexString();
+        }
+        unset($hsv);
+      }
+
+
+      for($tmp=$prec;$tmp<=100;$tmp+=$prec)
+      {
+        $hsv=new HSV($hue, $tmp, 100-$tmp);
+        if($returnedType=='HSV')
+        {
+          $hueValues[]=$hsv;
+        }
+        else
+        {
+          $hueValues[]=$hsv->getRGB()->getHexString();
+        }
+        unset($hsv);
+      }
+      for($tmp=$prec;$tmp<=100;$tmp+=$prec)
+      {
+        $hsv=new HSV($hue, $tmp, $tmp);
+        if($returnedType=='HSV')
+        {
+          $hueValues[]=$hsv;
+        }
+        else
+        {
+          $hueValues[]=$hsv->getRGB()->getHexString();
+        }
+        unset($hsv);
+      }
+
+      $returned[]=$hueValues;
+      unset($hueValues);
+    }
+
+    $hue=0;
+    $saturation=0;
+    $hueValues=Array();
+    //$prec=1/(count($returned[0])-2);
+    for($value=0;$value<=100;$value+=$prec/4)
+    {
+      $hsv=new HSV($hue, $saturation, round($value,0));
+      if($returnedType=='HSV')
+      {
+        $hueValues[]=$hsv;
+      }
+      else
+      {
+        $hueValues[]=$hsv->getRGB()->getHexString();
+      }
+      unset($hsv);
+    }
+
+    $returned[]=$hueValues;
+    unset($hueValues);
+
+    return($returned);
+  }
+
+  /**
+   * @param Array : an array
+   * @return Array : an array, giving the minimum value and the related key
+   */
+  static protected function min($values)
+  {
+    $minKey="";
+    $minValue=0;
+    foreach($values as $key => $val)
+    {
+      if($minKey=='' or $val<$minValue)
+      {
+        $minKey=$key;
+        $minValue=$val;
+      }
+    }
+    return(Array('key' => $minKey, 'value' => $minValue));
+  }
+
+  /**
+   * reverted sort color
+   *
+   */
+  static protected function sortTones($a, $b)
+  {
+    if($a['num'] == $b['num'])
+    {
+      return(0);
+    }
+    return ($a['num'] > $b['num']) ? -1 : 1;
+  }
+
+  /**
+   * @param Array : an array
+   * @return Array : an array, giving the maximum value and the related key
+   */
+  static protected function max($values)
+  {
+    $maxKey="";
+    $maxValue=0;
+    foreach($values as $key => $val)
+    {
+      if($maxKey=='' or $val>$maxValue)
+      {
+        $maxKey=$key;
+        $maxValue=$val;
+      }
+    }
+    return(Array('key' => $maxKey, 'value' => $maxValue));
+  }
+
+  /**
+   * check the validity for getFileColors() options
+   * if no parameters are given, return the default options values
+   *
+   * @param Array $options : an array with given options values
+   * @return Array : an array with valid options values
+   */
+  static protected function checkOptions($options=Array())
+  {
+    if(!is_array($options))
+    {
+      $options=Array();
+    }
+
+    if(!array_key_exists('quality', $options)) $options['quality']=1;
+    if(!array_key_exists('maxTime', $options)) $options['maxTime']=0;
+    if(!array_key_exists('pps', $options)) $options['pps']=0;
+    if(!array_key_exists('numColors', $options)) $options['numColors']=0;
+
+    if($options['quality']<=0) $options['quality']=1;
+    if($options['quality']>20) $options['quality']=20;
+    if($options['maxTime']<0) $options['maxTime']=0;
+    if($options['pps']<0) $options['pps']=0;
+    if($options['numColors']<0) $options['numColors']=0;
+
+    return($options);
+  }
+
+  static public function getColorFromTable(HSV $hsvObject, $colorTable)
+  {
+    $hue=360/(count($colorTable)-2);
+    $step=count($colorTable[0]);
+//echo "*hue:$hue<br>";
+//echo "*step:$step<br>";
+
+    $hsv=$hsvObject->get();
+
+    $hueNumber=round($hsv['H']/$hue,0);
+//echo "*hueNumber:$hueNumber<br>";
+
+//echo "*H:".$hsv['H']."<br>";
+//echo "*S:".$hsv['S']."<br>";
+//echo "*V:".$hsv['V']."<br>";
+
+    if($hsv['V']==0)
+    {
+//echo "-black-<br>";
+      // black
+      return(new RGB(0,0,0));
+    }
+    elseif($hsv['S']==0 && $hsv['V']==100)
+    {
+//echo "-white-<br>";
+      // white
+      return(new RGB(255,255,255));
+    }
+    elseif($hsv['S']==0 && $hsv['V']<100 && $hsv['V']>0)
+    {
+//echo "-grey-<br>";
+      // grey
+      $stepNumber=round($hsv['V']*($step-1)/100,0);
+      return($colorTable[count($colorTable)-1][$stepNumber]->getRGB());
+    }
+    elseif($hsv['S']==100 && $hsv['V']<100 && $hsv['V']>0)
+    {
+//echo "-value-<br>";
+      //color 'value'
+      $stepNumber=round($hsv['V']*$step/400,0);
+      return($colorTable[$hueNumber][$stepNumber]->getRGB());
+    }
+    elseif($hsv['V']==100 && $hsv['S']<100 && $hsv['S']>0)
+    {
+//echo "-saturation-<br>";
+      //color 'saturation'
+      $stepNumber=round(($step/4)+(100-$hsv['S'])*($step/400),0);
+      return($colorTable[$hueNumber][$stepNumber]->getRGB());
+    }
+    elseif($hsv['V']==100 && $hsv['S']==100)
+    {
+//echo "-pure-<br>";
+      //color 'pure'
+      $stepNumber=$step/4;
+      return($colorTable[$hueNumber][$stepNumber]->getRGB());
+    }
+    elseif(
+      ($hsv['V']<100 && $hsv['V']>50 && $hsv['S']<50 && $hsv['S']>0) ||
+      ($hsv['S']<100 && $hsv['S']>50 && $hsv['V']<50 && $hsv['V']>0))
+    {
+//echo "-desaturated 1-<br>";
+      //color 'desaturated'
+      $stepNumber=($step/2)+(100-$hsv['V'])*$step/400;
+      return($colorTable[$hueNumber][$stepNumber]->getRGB());
+    }
+    elseif($hsv['V']<100 && $hsv['V']>0 && $hsv['S']<100 && $hsv['S']>0)
+    {
+//echo "-desaturated 2-<br>";
+      //color 'desaturated'
+      $stepNumber=($step*0.75)+$hsv['V']*$step/400;
+      return($colorTable[$hueNumber][$stepNumber]->getRGB());
+    }
+//echo "-none-<br>";
+    return(new RGB(0,0,0));
+  }
+
+}
+
+
+
+
+
+
+?>
Index: /extensions/ColorStat/cstat_install.class.inc.php
===================================================================
--- /extensions/ColorStat/cstat_install.class.inc.php	(revision 5961)
+++ /extensions/ColorStat/cstat_install.class.inc.php	(revision 5961)
@@ -0,0 +1,136 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : ColorStat
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  CStat_Install : classe to manage plugin install
+
+  --------------------------------------------------------------------------- */
+
+   include_once('cstat_version.inc.php'); // => Don't forget to update this file !!
+   include_once('cstat_root.class.inc.php');
+   include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/GPCTables.class.inc.php');
+
+  /* CStat class for install process */
+  class CStat_Install extends CStat_root
+  {
+    private $tablef;
+
+    public function __construct($prefixeTable, $filelocation)
+    {
+      parent::__construct($prefixeTable, $filelocation);
+      $this->tablef= new GPCTables($this->tables);
+    }
+
+    public function __destruct()
+    {
+      unset($this->tablef);
+      parent::__destruct();
+    }
+
+    /*
+        function for installation process
+        return true if install process is ok, otherwise false
+    */
+    public function install()
+    {
+      $this->initConfig();
+      $this->loadConfig();
+      $this->config['installed']=CSTAT_VERSION2;
+      $this->config['newInstall']='y';
+      $this->saveConfig();
+
+      $tables_def=array(
+"CREATE TABLE `".$this->tables['color_table']."` (
+  `color_id` CHAR(6)  NOT NULL DEFAULT 000000,
+  `hue` INT UNSIGNED NOT NULL DEFAULT 0,
+  `saturation` INT UNSIGNED NOT NULL DEFAULT 0,
+  `value` INT UNSIGNED NOT NULL DEFAULT 0,
+  `num_images` INT UNSIGNED NOT NULL DEFAULT 0,
+  `num_pixels` INT UNSIGNED NOT NULL DEFAULT 0,
+  PRIMARY KEY (`color_id`),
+  INDEX `hue`(`hue`)
+)
+CHARACTER SET utf8 COLLATE utf8_general_ci",
+
+"CREATE TABLE `".$this->tables['images_colors']."` (
+  `image_id` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT 0,
+  `color_id` CHAR(6)  NOT NULL DEFAULT 000000,
+  `pct` float unsigned NOT NULL default '0',
+  `num_pixels` INT UNSIGNED NOT NULL DEFAULT 0,
+  PRIMARY KEY (`image_id`, `color_id`),
+  KEY `by_color` (`pct`,`color_id`)
+)
+CHARACTER SET utf8 COLLATE utf8_general_ci",
+
+"CREATE TABLE `".$this->tables['images']."` (
+  `image_id` mediumint(8) unsigned NOT NULL,
+  `analyzed` char(1) NOT NULL default 'n',
+  `num_colors` int(10) unsigned NOT NULL default '0',
+  `num_pixels` int(10) unsigned NOT NULL default '0',
+  `analyzed_pixels` int(10) unsigned NOT NULL default '0',
+  `pps` int(10) unsigned NOT NULL default '0',
+  `time` float unsigned NOT NULL default '0',
+  `quality` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY  (`image_id`),
+  KEY `by_analyzed` (`analyzed`)
+)",
+
+      );
+
+      $result=$this->tablef->create($tables_def);
+      return($result);
+    }
+
+
+    /*
+        function for uninstall process
+    */
+    public function uninstall()
+    {
+      $this->deleteConfig();
+      $this->tablef->drop();
+      return('');
+    }
+
+    public function activate()
+    {
+      global $template;
+
+      $this->initConfig();
+      //$this->loadConfig(); //don't keep the previous config : we need to start with default values
+      $this->config['installed']=CSTAT_VERSION2;
+      $this->config['newInstall']='y';
+      $this->saveConfig();
+
+      pwg_query("DELETE FROM ".$this->tables['color_table']);
+      pwg_query("DELETE FROM ".$this->tables['images_colors']);
+      pwg_query("UPDATE ".$this->tables['images']."
+                  SET analyzed='n',
+                      num_colors=0,
+                      num_pixels=0,
+                      analyzed_pixels=0,
+                      pps=0,
+                      time=0,
+                      quality=0;");
+      pwg_query("INSERT INTO ".$this->tables['images']."
+                  SELECT id, 'n', 0, 0, 0, 0, 0, 0
+                    FROM ".IMAGES_TABLE."
+                    WHERE id NOT IN (SELECT image_id FROM ".$this->tables['images'].")");
+
+      return('');
+    }
+
+    public function deactivate()
+    {
+    }
+
+  } //class
+
+?>
Index: /extensions/ColorStat/cstat_pip.class.inc.php
===================================================================
--- /extensions/ColorStat/cstat_pip.class.inc.php	(revision 5961)
+++ /extensions/ColorStat/cstat_pip.class.inc.php	(revision 5961)
@@ -0,0 +1,192 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : LMT
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  LMT_PIP : classe to manage plugin public pages
+
+  --------------------------------------------------------------------------- */
+
+include_once('lmt_root.class.inc.php');
+//include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/GPCPublicIntegration.class.inc.php');
+
+class LMT_PIP extends LMT_root
+{
+  protected $section_page;
+
+  public function __construct($prefixeTable, $filelocation)
+  {
+    parent::__construct($prefixeTable, $filelocation);
+    $this->loadConfig();
+
+    $this->initEvents();
+    $this->load_lang();
+  }
+
+  public function __destruct()
+  {
+    unset($section_page);
+    parent::__destruct();
+  }
+
+  /*
+    load language file
+  */
+  public function load_lang()
+  {
+    global $lang;
+
+    load_language('plugin.lang', LMT_PATH);
+
+    // ajax is managed here ; this permit to use user&language properties inside
+    // ajax content
+    //$this->return_ajax_content();
+  }
+
+  /*
+    initialize events call for the plugin
+  */
+  public function initEvents()
+  {
+    parent::initEvents();
+/*
+    add_event_handler('blockmanager_apply', array(&$this, 'blockmanager_apply') );
+    add_event_handler('loading_lang', array(&$this, 'load_lang'));
+*/
+    if($this->config['lmt_licence_activated']=='y')
+    {
+      add_event_handler('loc_end_page_header', array(&$this->css_icn, 'applyCSS'));
+      add_event_handler('loc_end_picture', array(&$this, 'manage_licence_element'));
+
+      if($this->config['lmt_warning_visible']=='y')
+      {
+        add_event_handler('loc_end_page_tail', array(&$this, 'manage_warning_text'));
+      }
+    }
+  }
+
+
+
+  /* -------------------------------------------------------------------------
+    FUNCTIONS TO MANAGE LMT DISPLAY
+  ------------------------------------------------------------------------- */
+  public function manage_licence_element()
+  {
+    global $template, $page, $user;
+
+    $licence=$this->get_image_licence($page['image_id']);
+    if($licence['licence']=="")
+    {
+      return("");
+    }
+
+    if($this->config['lmt_redirect_activated']=='y')
+    {
+      $url=$this->config['lmt_redirect_url-'.strToLower($licence['licence'])][$user['language']];
+      if($url=='')
+      {
+        $url=$this->config['lmt_redirect_url-'.strToLower($licence['licence'])]['en_UK'];
+      }
+    }
+    else
+    {
+      $url="";
+    }
+
+    $style="";
+    $text="";
+    $target=($this->config['lmt_redirect_open_target']=="y")?" onclick='window.open(this.href); return false;'":"";
+    switch($this->config['lmt_licence_logo'])
+    {
+      case '80x15':
+        if($url!="")
+        {
+          $text = "<br/><a href='".$url."'".$target."><img class='logo80x15' src='". LMT_PATH."img/".strToLower($licence['licence'])."_80x15.png'></a>".$licence['aut_text1']." ".$licence['aut_text2'];
+        }
+        else
+        {
+          $text = "<br/><img class='logo80x15' src='". LMT_PATH."img/".strToLower($licence['licence'])."_80x15.png'>".$licence['aut_text1']." ".$licence['aut_text2'];
+        }
+      break;
+      case '88x31';
+        $style=" style='text-align:left;'";
+        if($url!="")
+        {
+          $text = "<table style='margin:auto;'><tr><td><a href='".$url."'".$target."><img class='logo88x31' style='top:-4px;' src='". LMT_PATH."img/".strToLower($licence['licence'])."_88x31.png'></a></td><td>".$licence['aut_text1']."<br/>".$licence['aut_text2']."</td></tr></table>";
+        }
+        else
+        {
+          $text = "<table style='margin:auto;'><tr><td><img class='logo88x31' style='top:-4px;' src='". LMT_PATH."img/".strToLower($licence['licence'])."_88x31.png'></td><td>".$licence['aut_text1']."<br/>".$licence['aut_text2']."</td></tr></table>";
+        }
+        break;
+      case 'text';
+        if($url!="")
+        {
+          $text ="<br/>".l10n("lmt_lbl_under-".strToLower($licence['licence']))." <a href='".$url."'".$target.">".l10n("lmt_lbl_cc_s-".strToLower($licence['licence']))."</a> ".$licence['aut_text1']." ".$licence['aut_text2'];
+        }
+        else
+        {
+          $text ="<br/>".l10n("lmt_lbl_under-".strToLower($licence['licence']))." ".l10n("lmt_lbl_cc_s-".strToLower($licence['licence']))." ".$licence['aut_text1']." ".$licence['aut_text2'];
+        }
+        break;
+    }
+
+    $template->concat('COMMENT_IMG', '<span class="licencetag" '.$style.'>'.$text.'</span>');
+  }
+
+  public function manage_warning_text()
+  {
+    global $template, $user;
+
+
+    if(isset($this->config['lmt_warning_texts'][$user['language']]))
+    {
+      $text=$this->config['lmt_warning_texts'][$user['language']];
+    }
+    else
+    {
+      $text=$this->config['lmt_warning_texts']['en_UK'];
+    }
+
+    $patterns = array('/\[logo=80x15\]/i', '/\[logo=88x31\]/i', '/\[logo=text\]/i');
+    $replacements = array(
+      "<img class='logo80x15' src='". LMT_PATH."img/".strToLower($this->config['lmt_licence_default'])."_80x15.png'>",
+      "<img class='logo88x31' src='". LMT_PATH."img/".strToLower($this->config['lmt_licence_default'])."_88x31.png'>",
+      l10n("lmt_lbl_cc_s-".strToLower($this->config['lmt_licence_default']))
+    );
+
+    if($this->config['lmt_redirect_activated']=='y')
+    {
+      $url=$this->config['lmt_redirect_url-'.strToLower($this->config['lmt_licence_default'])][$user['language']];
+      if($url=='')
+      {
+        $url=$this->config['lmt_redirect_url-'.strToLower($this->config['lmt_licence_default'])]['en_UK'];
+      }
+      if($url!="")
+      {
+        $target=($this->config['lmt_redirect_open_target']=="y")?" onclick='window.open(this.href); return false;'":"";
+        $replacements[0]="<a href='".$url."'".$target.">".$replacements[0]."</a>";
+        $replacements[1]="<a href='".$url."'".$target.">".$replacements[1]."</a>";
+        $replacements[2]="<a href='".$url."'".$target.">".$replacements[2]."</a>";
+      }
+    }
+
+    $text = preg_replace($patterns, $replacements, $text);
+
+    $template->append("footer_elements", "<span>".htmlspecialchars_decode($text)."</span>");
+  }
+
+
+  /* ---------------------------------------------------------------------------
+    ajax functions
+  --------------------------------------------------------------------------- */
+
+} //class
+
+?>
Index: /extensions/ColorStat/cstat_root.class.inc.php
===================================================================
--- /extensions/ColorStat/cstat_root.class.inc.php	(revision 5961)
+++ /extensions/ColorStat/cstat_root.class.inc.php	(revision 5961)
@@ -0,0 +1,199 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : ColorStat
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  CStat_root : common classe for admin and public classes
+
+  --------------------------------------------------------------------------- */
+  include_once('cstat_colorstat.class.inc.php');
+  include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/CommonPlugin.class.inc.php');
+  include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/GPCCss.class.inc.php');
+  include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/GPCAjax.class.inc.php');
+
+  class CStat_root extends CommonPlugin
+  {
+    protected $css;   //the css object
+    protected $colorTableSize=Array('small' => Array(30,20), 'large' => Array(10,10));
+
+    public function __construct($prefixeTable, $filelocation)
+    {
+      $this->setPluginName('ColorStat');
+      $this->setPluginNameFiles("cstat");
+      parent::__construct($prefixeTable, $filelocation);
+      $this->section_name=$this->getPluginNameFiles();
+
+      $this->setTablesList(array('images', 'color_table', 'images_colors'));
+
+
+      $this->css = new GPCCss(dirname($this->getFileLocation()).'/'.$this->getPluginNameFiles().".css");
+    }
+
+    public function __destruct()
+    {
+      unset($this->css);
+      parent::__destruct();
+    }
+
+    public function initEvents()
+    {
+      parent::initEvents();
+      add_event_handler('blockmanager_register_blocks', array(&$this, 'register_blocks') );
+    }
+
+    /*
+      menu block management
+    */
+    public function register_blocks()
+    {
+    }
+
+    /*
+      intialize default values
+    */
+    public function initConfig()
+    {
+      //global $user;
+      $this->config=array(
+        'newInstall' => 'n',
+        'analyze.maxTime' => 0.1,
+        'analyze.colorTable' => 'small',
+        'analyze.pps' => 0,
+        'analyze.itemPerRequest' => 10,
+        'display.stat.orderType' => 'img',
+      );
+    }
+
+
+    /**
+     * return HTML code for a given colorTable
+     *
+     * @param Array $colorTable : a color table, typically made with the
+     *                            ColorStat::getColorTable() function
+     * @param Int $size         : size for colorbox in the HTML table
+     * @return String : HTML code
+     */
+    public function htmlColorTable($colorTable, $size=5, $id="", $class="")
+    {
+      global $template;
+
+      $template->set_filename('color_table_page',
+                    dirname($this->getFileLocation()).'/templates/cstat_color_table.tpl');
+
+      $nbHue=count($colorTable);
+      $nbStep=count($colorTable[0]);
+      $colors=Array();
+      for($step=0;$step<$nbStep;$step++)
+      {
+        $row=Array();
+        for($hue=0;$hue<$nbHue;$hue++)
+        {
+
+          if($colorTable[$hue][$step] instanceof HSV)
+          {
+            $row[]=Array('color' => $colorTable[$hue][$step]->getRGB()->getHexString(), 'pct' => "", 'num' => "");
+          }
+          elseif(is_array($colorTable[$hue][$step]))
+          {
+            $row[]=Array(
+              'color' => (array_key_exists('color', $colorTable[$hue][$step]))?$colorTable[$hue][$step]['color']:"",
+              'pct' => (array_key_exists('pct', $colorTable[$hue][$step]))?$colorTable[$hue][$step]['pct']:"",
+              'num' => (array_key_exists('num', $colorTable[$hue][$step]))?$colorTable[$hue][$step]['num']:"",
+            );
+          }
+          else
+          {
+            $row[]=Array('color' => $colorTable[$hue][$step], 'pct' => "", 'num' => "");
+          }
+        }
+        $colors[]=$row;
+        unset($row);
+      }
+
+      $data=array(
+        'colorTable' => $colors,
+        'size' => $size,
+        'id' => $id,
+        'class' => $class
+      );
+
+      $template->assign('data', $data);
+      unset($data);
+
+      return($template->parse('color_table_page', true));
+    }
+
+    /**
+     * return HTML code for a given colors list
+     *
+     * @param Array $colors : list of colors
+     * @param Int $size     : size for colorbox in the HTML table
+     * @return String : HTML code
+     */
+    public function htmlColorList($colorList, $split=8, $size=5, $id="", $class="")
+    {
+      global $template;
+
+      $template->set_filename('color_table_page',
+                    dirname($this->getFileLocation()).'/templates/cstat_color_table.tpl');
+
+      $colors=Array();
+
+      $row=0;
+      $num=0;
+      foreach($colorList as $key => $val)
+      {
+        $colors[$row][]=Array('color' => $key, 'pct' => $val['pct'], 'num' => "");
+        $num++;
+        if($num==$split)
+        {
+          $num=0;
+          $row++;
+        }
+      }
+
+      $data=array(
+        'colorTable' => $colors,
+        'size' => $size,
+        'id' => $id,
+        'class' => $class
+      );
+
+      $template->assign('data', $data);
+      unset($data);
+
+      return($template->parse('color_table_page', true));
+    }
+
+
+
+
+    protected function displayResult($action_msg, $result)
+    {
+      global $page;
+
+      if($result)
+      {
+        array_push($page['infos'], $action_msg);
+      }
+      else
+      {
+        array_push($page['errors'], $action_msg);
+      }
+    }
+
+
+    /* ---------------------------------------------------------------------------
+      ajax functions
+    --------------------------------------------------------------------------- */
+
+
+  } //class
+
+?>
Index: /extensions/ColorStat/cstat_version.inc.php
===================================================================
--- /extensions/ColorStat/cstat_version.inc.php	(revision 5961)
+++ /extensions/ColorStat/cstat_version.inc.php	(revision 5961)
@@ -0,0 +1,19 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : ColorStat
+  Author     : Grum
+    email    : grum@grum.fr
+    website  : http://photos.grum.fr
+    PWG user : http://forum.piwigo.org/profile.php?id=3706
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  --------------------------------------------------------------------------- */
+
+  if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+  define('CSTAT_VERSION',  '0.1.0');
+  define('CSTAT_VERSION2', '00.01.00');
+?>
Index: /extensions/ColorStat/index.php
===================================================================
--- /extensions/ColorStat/index.php	(revision 5961)
+++ /extensions/ColorStat/index.php	(revision 5961)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | 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/ColorStat/language/en_UK/description.txt
===================================================================
--- /extensions/ColorStat/language/en_UK/description.txt	(revision 5961)
+++ /extensions/ColorStat/language/en_UK/description.txt	(revision 5961)
@@ -0,0 +1,1 @@
+Statistical analysis and research on color
Index: /extensions/ColorStat/language/en_UK/index.php
===================================================================
--- /extensions/ColorStat/language/en_UK/index.php	(revision 5961)
+++ /extensions/ColorStat/language/en_UK/index.php	(revision 5961)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | 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/ColorStat/language/en_UK/plugin.lang.php
===================================================================
--- /extensions/ColorStat/language/en_UK/plugin.lang.php	(revision 5961)
+++ /extensions/ColorStat/language/en_UK/plugin.lang.php	(revision 5961)
@@ -0,0 +1,73 @@
+<?php
+
+$lang['Grum Plugin Classes is not installed'] = 'The plugin <b>Grum Plugin Classes</b> is not installed';
+
+$lang['cstat_release'] = 'v';
+$lang['cstat_ok']='OK';
+
+$lang['cstat_install'] = 'Installation';
+$lang['cstat_step_1'] = 'Choice of reference color';
+$lang['cstat_step_1_help'] = "
+The analysis performed by the plugin is to perform, for each color found in an image, a comparison with a color belonging to a defined range.
+Before you can use the plugin, it is necessary to select the range on which to work.
+
+Two ranges are offered:";
+$lang['cstat_small_colortable'] = 'Narrow range';
+$lang['cstat_large_colortable'] = 'Extended range';
+$lang['cstat_help_small_color_table'] = "
+Working with a limited range of colors increases the probability of reference tones minority. This has the advantage of allowing searches on wider range of colors.
+
+In return, the variation of shades is smaller, the relevance of results when searching on a particular color can be very convincing.";
+$lang['cstat_help_large_color_table'] = "
+Working on a wide range of colors can have an increased number of grades to a given color. This has the advantage of allowing more precise queries on a range of colors more accurately and thus increase the relevance of results.
+
+In return, an image with one or two shades predominantly present, the variation of the nuances of these consequences will greatly reduce the probability of reference colors minority.";
+$lang['cstat_sample_color_associated'] = 'Colors of the associated range:';
+$lang['cstat_color'] = 'Color';
+$lang['cstat_validate'] = 'Submit';
+
+
+$lang['cstat_database'] = 'Repository';
+$lang['cstat_loading'] = 'Loading...';
+$lang['cstat_update_color_database']= 'Update the repository of colors';
+$lang['cstat_status_of_database']='State of repository';
+$lang['cstat_analyze_not_analyzed_pictures'] = "The analysis focuses on the images that have never been analyzed, and adds to the existing repository";
+$lang['cstat_analyze_all_pictures'] = "The analysis includes all the images in the gallery, and replaces the current repository";
+$lang['cstat_analyze_caddie_add_pictures'] = "The analysis focuses on the images in the basket, and adds to the existing repository";
+$lang['cstat_analyze_caddie_replace_pictures'] = "The analysis focuses on the images in the basket, and replaces the current repository";
+$lang['cstat_analyze'] = "Analyze";
+$lang['cstat_need_to_analyze'] = "To have a reference color, it is necessary to conduct a direct analysis of the gallery:";
+$lang['cstat_warning_on_analyze_0'] = "Warning !";
+$lang['cstat_warning_on_analyze_1'] = "Building the repository with the direct analysis process might be long (up to several minutes of treatment) and resource-consuming for the server, depending on the number of photos selected for analysis.";
+$lang['cstat_warning_on_analyze_2'] = "This type of use may be penalized by some hosts.";
+
+$lang['cstat_updating_database']="Update repository";
+$lang['cstat_numberOfAnalyzedPictures']="%d images have been analyzed";
+$lang['cstat_numberOfNotAnalyzedPictures']="%d images have not been analyzed";
+$lang['cstat_numberOfPicturesInError']="%d images could not be analyzed (processing error)";
+
+$lang['cstat_analyze_in_progress']="Analyze in progress...";
+$lang['cstat_analyze_is_finished']="Analyze completed";
+
+$lang['cstat_stat']='Statistics';
+$lang['cstat_statistics']='Statistical analysis';
+$lang['cstat_number_of_colors_used']='Number of colors used:';
+
+
+$lang['cstat_colors']='Colors';
+$lang['cstat_Pct']='%';
+$lang['cstat_NumOfImages']='Number of images';
+$lang['cstat_NumOfPixels']='Number of pixels';
+$lang['cstat_NumOfImages_help']="Indicates the number of images in which color is present. The percentage is relative to the number of images analyzed.";
+$lang['cstat_NumOfPixels_help']="Indicates the number of pixels for which color has been determined. The percentage is relative to the number of pixels analyzed and represents the 'area' occupied on all photos.";
+$lang['cstat_images']='images';
+$lang['cstat_surface']='surface';
+
+
+$lang['cstat_search']='Search';
+$lang['cstat_config']='Configuration';
+
+$lang['cstat_search_by_color']='Search by color';
+$lang['cstat_config_plugin']='Configuring the plugin';
+
+?>
Index: /extensions/ColorStat/language/fr_FR/description.txt
===================================================================
--- /extensions/ColorStat/language/fr_FR/description.txt	(revision 5961)
+++ /extensions/ColorStat/language/fr_FR/description.txt	(revision 5961)
@@ -0,0 +1,1 @@
+Analyses statistiques & recherches sur les couleurs
Index: /extensions/ColorStat/language/fr_FR/index.php
===================================================================
--- /extensions/ColorStat/language/fr_FR/index.php	(revision 5961)
+++ /extensions/ColorStat/language/fr_FR/index.php	(revision 5961)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | 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/ColorStat/language/fr_FR/plugin.lang.php
===================================================================
--- /extensions/ColorStat/language/fr_FR/plugin.lang.php	(revision 5961)
+++ /extensions/ColorStat/language/fr_FR/plugin.lang.php	(revision 5961)
@@ -0,0 +1,77 @@
+<?php
+
+/* -----------------------------------------------------------------------------
+
+----------------------------------------------------------------------------- */
+
+$lang['Grum Plugin Classes is not installed'] = 'Le plugin <b>Grum Plugin Classes</b> n\'est pas installé';
+
+$lang['cstat_release'] = 'v';
+$lang['cstat_ok']='OK';
+
+$lang['cstat_install'] = 'Installation';
+$lang['cstat_step_1'] = 'Choix du référentiel colorimétrique';
+$lang['cstat_step_1_help'] = "
+L'analyse effectuée par le plugin consiste à, pour chaque couleur trouvée dans une image, effectuer un rapprochement avec une couleur appartenant à une gamme définie.
+Avant de pouvoir utiliser le plugin, il est donc nécessaire de sélectionner la gamme sur laquelle travailler.
+
+Deux gammes sont proposées :";
+$lang['cstat_small_colortable'] = 'Gamme réduite';
+$lang['cstat_large_colortable'] = 'Gamme élargie';
+$lang['cstat_help_small_color_table'] = "
+Travailler sur une gamme réduite de couleurs augmente la probabilité de référencer des teintes minoritaires. Ceci a pour avantage de permettre d'effectuer des recherches sur des gammes de couleurs plus larges.
+
+En contrepartie, la variation des nuances étant plus réduite, la pertinence des résultats lors de la recherche sur une couleur particulière peut s'avérer peu probante.";
+$lang['cstat_help_large_color_table'] = "
+Travailler sur une gamme élargie de couleurs permet de disposer d'un nombre accru de nuances pour une teinte donnée. Ceci a pour avantage de permettre d'affiner les recherches sur une gamme de couleurs plus précise et augmenter ainsi la pertinence des résultats.
+
+En contrepartie, sur une image avec une ou deux teintes majoritairement présentes, la variation des nuances de celles-ci aura pour conséquences de réduire fortement la probabilité de référencer les teintes minoritaires.";
+$lang['cstat_sample_color_associated'] = 'Couleurs de la gamme associée :';
+$lang['cstat_color'] = 'Couleur';
+$lang['cstat_validate'] = 'Valider';
+
+
+$lang['cstat_database'] = 'Référentiel';
+$lang['cstat_loading'] = 'Chargement...';
+$lang['cstat_update_color_database']= 'Mettre à jour le référentiel des couleurs';
+$lang['cstat_status_of_database']='Etat du référentiel';
+$lang['cstat_analyze_not_analyzed_pictures'] = "L'analyse porte sur les images n'ayant jamais été analysées et vient s'ajouter au référentiel actuel";
+$lang['cstat_analyze_all_pictures'] = "L'analyse porte sur toutes les images de la galerie et vient remplacer le référentiel actuel";
+$lang['cstat_analyze_caddie_add_pictures'] = "L'analyse porte sur les images du panier et vient s'ajouter au référentiel actuel";
+$lang['cstat_analyze_caddie_replace_pictures'] = "L'analyse porte sur les images du panier et vient remplacer le référentiel actuel";
+$lang['cstat_analyze'] = "Analyser";
+$lang['cstat_need_to_analyze'] = "Afin de disposer d'un référentiel de couleur, il est nécessaire de procéder à une analyse directe de la galerie :";
+$lang['cstat_warning_on_analyze_0'] = "Attention !";
+$lang['cstat_warning_on_analyze_1'] = "L'alimentation du référentiel via le processus d'analyse directe peut s'avérer être long (jusqu'à plusieurs minutes de traitement) et gourmand en ressources sur le serveur en fonction du nombre de photos sélectionnées pour l'analyse.";
+$lang['cstat_warning_on_analyze_2'] = "Certains hébergeurs peuvent sanctionner ce type d'usage.";
+
+$lang['cstat_updating_database']="Mise à jour du référentiel";
+$lang['cstat_numberOfAnalyzedPictures']="%d images ont fait l'objet d'une analyse";
+$lang['cstat_numberOfNotAnalyzedPictures']="%d images n'ont pas fait l'objet d'une analyse";
+$lang['cstat_numberOfPicturesInError']="%d images n'ont pas pu être analysées (traitement en erreur)";
+
+$lang['cstat_analyze_in_progress']='Traitement en cours...';
+$lang['cstat_analyze_is_finished']='Traitement terminé';
+
+$lang['cstat_stat']='Statistiques';
+$lang['cstat_statistics']='Analyses statistiques';
+$lang['cstat_number_of_colors_used']='Nombre de couleurs utilisées :';
+
+
+$lang['cstat_colors']='Couleurs';
+$lang['cstat_Pct']='%';
+$lang['cstat_NumOfImages']='Nombre d\'images';
+$lang['cstat_NumOfPixels']='Nombre de pixels';
+$lang['cstat_NumOfImages_help']="Indique le nombre d'images dans lesquelles la couleur est présente. Le pourcentage est relatif au nombre d'images analysées.";
+$lang['cstat_NumOfPixels_help']="Indique le nombre de pixels pour lesquels la couleur a été déterminée. Le pourcentage est relatif au nombre de pixels analysés et représente la 'surface' occupée sur l'ensemble des photos.";
+$lang['cstat_images']='images';
+$lang['cstat_surface']='surface';
+
+
+$lang['cstat_search']='Recherche';
+$lang['cstat_config']='Configuration';
+
+$lang['cstat_search_by_color']='Effectuer une recherche par couleur';
+$lang['cstat_config_plugin']='Configuration du plugin';
+
+?>
Index: /extensions/ColorStat/language/index.php
===================================================================
--- /extensions/ColorStat/language/index.php	(revision 5961)
+++ /extensions/ColorStat/language/index.php	(revision 5961)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | 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/ColorStat/main.inc.php
===================================================================
--- /extensions/ColorStat/main.inc.php	(revision 5961)
+++ /extensions/ColorStat/main.inc.php	(revision 5961)
@@ -0,0 +1,95 @@
+<?php
+/*
+Plugin Name: ColorStat
+Version: 0.1.0
+Description: Allow to make stat on pictures colors
+Plugin URI: http://phpwebgallery.net/ext/extension_view.php?eid=
+Author: grum@piwigo.org
+Author URI: http://photos.grum.fr
+*/
+
+/*
+--------------------------------------------------------------------------------
+  Author     : Grum
+    email    : grum@piwigo.com
+    website  : http://photos.grum.fr
+    PWG user : http://forum.phpwebgallery.net/profile.php?id=3706
+
+    << May the Little SpaceFrog be with you ! >>
+--------------------------------------------------------------------------------
+
+:: HISTORY
+
+| release | date       |
+| 0.1.0   | 2010/04/21 | start to coding
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+
+
+:: TO DO
+
+--------------------------------------------------------------------------------
+
+:: NFO
+  CStat_root : common classe for admin and public classes
+  CStat_AIM  : classe to manage plugin integration into plugin menu
+  CStat_AIP  : classe to manage plugin admin pages
+  CStat_PIP  : classe to manage plugin public pages
+
+--------------------------------------------------------------------------------
+*/
+
+// pour faciliter le debug :o)
+ //ini_set('error_reporting', E_ALL);
+ //ini_set('display_errors', true);
+
+if(!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+
+define('CSTAT_DIR' , basename(dirname(__FILE__)));
+define('CSTAT_PATH' , PHPWG_PLUGINS_PATH . CSTAT_DIR . '/');
+
+include_once('cstat_version.inc.php'); // => Don't forget to update this file !!
+
+global $prefixeTable;
+
+if(defined('IN_ADMIN'))
+{
+  //CStat admin interface loaded and active only if in admin page
+  include_once("cstat_aim.class.inc.php");
+  $obj=new CStat_AIM($prefixeTable, __FILE__);
+  $obj->initEvents();
+  set_plugin_data($plugin['id'], $obj);
+}
+else
+{
+  //CStat public interface loaded and active only if in public page
+  /*include_once("cstat_pip.class.inc.php");
+  $obj=new CStat_PIP($prefixeTable, __FILE__);
+  set_plugin_data($plugin['id'], $obj);
+  */
+}
+
+
+
+?>
Index: /extensions/ColorStat/maintain.inc.php
===================================================================
--- /extensions/ColorStat/maintain.inc.php	(revision 5961)
+++ /extensions/ColorStat/maintain.inc.php	(revision 5961)
@@ -0,0 +1,128 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : ColorStat
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  --------------------------------------------------------------------------- */
+
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+if(!defined('CSTAT_DIR')) define('CSTAT_DIR' , basename(dirname(__FILE__)));
+if(!defined('CSTAT_PATH')) define('CSTAT_PATH' , PHPWG_PLUGINS_PATH . CSTAT_DIR . '/');
+
+//ini_set('error_reporting', E_ALL);
+//ini_set('display_errors', true);
+
+global $gpc_installed, $gpcNeeded, $lang; //needed for plugin manager compatibility
+
+/* -----------------------------------------------------------------------------
+ColorStat needs the Grum Plugin Classe
+----------------------------------------------------------------------------- */
+$gpc_installed=false;
+$gpcNeeded="3.1.0";
+if(file_exists(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/CommonPlugin.class.inc.php'))
+{
+  include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/CommonPlugin.class.inc.php');
+  // need GPC release greater or equal than 3.1.0
+  if(CommonPlugin::checkGPCRelease(3,1,0))
+  {
+    include_once('cstat_install.class.inc.php');
+    $gpc_installed=true;
+  }
+}
+
+function gpcMsgError(&$errors)
+{
+  global $gpcNeeded;
+  $msg=sprintf(l10n('To install this plugin, you need to install Grum Plugin Classes %s before'), $gpcNeeded);
+  if(is_array($errors))
+  {
+    array_push($errors, $msg);
+  }
+  else
+  {
+    $errors=Array($msg);
+  }
+}
+// -----------------------------------------------------------------------------
+
+
+
+
+load_language('plugin.lang', CSTAT_PATH);
+
+
+function plugin_install($plugin_id, $plugin_version, &$errors)
+{
+  global $prefixeTable, $gpc_installed, $gpcNeeded;
+
+  if($gpc_installed)
+  {
+    $obj = new CStat_Install($prefixeTable, __FILE__);
+    $result=$obj->install();
+    if(!$result)
+    {
+      array_push($errors, "error");
+    }
+    GPCCore::register($obj->getPluginName(), CSTAT_VERSION, $gpcNeeded);
+  }
+  else
+  {
+    gpcMsgError($errors);
+  }
+}
+
+function plugin_activate($plugin_id, $plugin_version, &$errors)
+{
+  global $prefixeTable, $gpc_installed;
+
+  if($gpc_installed)
+  {
+    $obj = new CStat_Install($prefixeTable, __FILE__);
+    $result=$obj->activate();
+    if($result===false or $result!='')
+    {
+      if(is_string($result))
+      {
+        array_push($errors, $result);
+      }
+      else
+      {
+        array_push($errors, "");
+      }
+    }
+  }
+  else
+  {
+    gpcMsgError($errors);
+  }
+}
+
+function plugin_deactivate($plugin_id)
+{
+}
+
+function plugin_uninstall($plugin_id)
+{
+  global $prefixeTable, $gpc_installed;
+
+  if($gpc_installed)
+  {
+    $obj = new CStat_Install($prefixeTable, __FILE__);
+    $obj->uninstall();
+    GPCCore::unregister($obj->getPluginName());
+  }
+  else
+  {
+    gpcMsgError($errors);
+  }
+}
+
+
+?>
Index: /extensions/ColorStat/templates/cstat_color_table.tpl
===================================================================
--- /extensions/ColorStat/templates/cstat_color_table.tpl	(revision 5961)
+++ /extensions/ColorStat/templates/cstat_color_table.tpl	(revision 5961)
@@ -0,0 +1,10 @@
+<table {if $data.id!=''}id="{$datas.id}"{/if} {if $data.class!=''}class="{$data.class}"{/if} style="border-collapse:collapse;">
+  {foreach from=$data.colorTable item=row}
+  <tr>
+    {foreach from=$row item=col}
+    <td style="width:{$data.size}px;height:{$data.size}px;background-color:#{$col.color};"
+        title="{'cstat_color'|@translate}&nbsp;#{$col.color} {if $col.num!=''}&nbsp;-&nbsp;{$col.num}&nbsp;{'cstat_images'|@translate}{/if} {if $col.pct!=''}&nbsp;-&nbsp;{'cstat_surface'|@translate}&nbsp;{$col.pct}%{/if} "></td>
+    {/foreach}
+  </tr>
+  {/foreach}
+</table>
