source: extensions/Histogram/hgram_histogram.class.inc.php @ 32824

Last change on this file since 32824 was 15346, checked in by grum, 13 years ago

feature:2640 - Compatibility with Piwigo 2.4

  • Property svn:executable set to *
File size: 11.1 KB
Line 
1<?php
2/* -----------------------------------------------------------------------------
3  Plugin     : Histogram
4  Author     : Grum
5    email    : grum@grum.fr
6    website  : http://photos.grum.fr
7    PWG user : http://forum.piwigo.org/profile.php?id=3706
8
9    << May the Little SpaceFrog be with you ! >>
10  ------------------------------------------------------------------------------
11  See main.inc.php for release information
12
13  Provided classes :
14
15
16  --------------------------------------------------------------------------- */
17
18if(!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
19
20define('MAX_PIXELS_ANALYZED', 1000000);
21
22
23class Histogram {
24  static public $fileHistogram = Array(
25    'pixels' => 0,
26    'analyzed' => 0,
27    'time' => 0,
28    'fileName' => "",
29  );
30
31  /**
32   * returns histogram values for an image
33   *
34   *
35   * @param String $fileName : the picture's filename
36   * @return : -1 if file doesn't exist
37   *           -2 if file is not a PNG, a JPEG or a GIF file
38   *           -3 if a fatal error occurs
39   *            Array of L, R, G, and B values (% for values from 0 to 255)
40   */
41  static function read($fileName)
42  {
43    self::$fileHistogram=Array(
44      'pixels'   => 0,
45      'analyzed' => 0,
46      'time' => 0,
47      'pps' =>0,
48    );
49
50    $returned=array(
51      'L' => array(),
52      'A' => array(),
53      'M' => array(),
54      'R' => array(),
55      'G' => array(),
56      'B' => array()
57    );
58
59    for($i=0;$i<256;$i++)
60    {
61      $returned['L'][$i]=0;
62      $returned['A'][$i]=0;
63      $returned['M'][$i]=0;
64      $returned['R'][$i]=0;
65      $returned['G'][$i]=0;
66      $returned['B'][$i]=0;
67    }
68
69    if(file_exists($fileName))
70    {
71      $time=microtime(true);
72
73      try
74      {
75        if(preg_match('/.*\.gif$/i', $fileName))
76        {
77          $image = imagecreatefromgif($fileName);
78        }
79        elseif(preg_match('/.*\.(jpg|jpeg)$/i', $fileName))
80        {
81          $image = imagecreatefromjpeg($fileName);
82        }
83        elseif(preg_match('/.*\.png$/i', $fileName))
84        {
85          $image = imagecreatefrompng($fileName);
86        }
87        else
88        {
89          return(-2);
90        }
91
92        $imageWidth=imagesx($image);
93        $imageHeight=imagesy($image);
94
95
96        $ratio=1;
97        $nbPixels=$imageWidth*$imageHeight;
98        if($nbPixels>MAX_PIXELS_ANALYZED) $ratio=$nbPixels/MAX_PIXELS_ANALYZED;
99
100        $imageWorkWidth=round($imageWidth/$ratio,0);
101        $imageWorkHeight=round($imageHeight/$ratio,0);
102        $imageWork=imagecreatetruecolor($imageWorkWidth,$imageWorkHeight);
103        imagecopyresampled($imageWork, $image, 0, 0, 0, 0, $imageWorkWidth, $imageWorkHeight, $imageWidth, $imageHeight);
104        //imagecopyresized($imageWork, $image, 0, 0, 0, 0, $imageWorkWidth, $imageWorkHeight, $imageWidth, $imageHeight);
105        imagedestroy($image);
106
107        $i=0;
108        for($px=0;$px<$imageWorkWidth;$px++)
109        {
110          for($py=0;$py<$imageWorkHeight;$py++)
111          {
112            $i++;
113            $value=imagecolorat($imageWork, $px, $py);
114
115            $rgb=self::IntToRGB($value);
116            $l=self::RGBtoL($rgb);
117            $a=self::RGBtoA($rgb);
118            $m=self::RGBtoM($rgb);
119
120            $returned['L'][$l]++;
121            $returned['A'][$a]++;
122            $returned['M'][$m]++;
123            $returned['R'][$rgb['R']]++;
124            $returned['G'][$rgb['G']]++;
125            $returned['B'][$rgb['B']]++;
126
127            unset($rgb);
128          }
129        }
130
131        imagedestroy($imageWork);
132
133        self::$fileHistogram=Array(
134          'pixels'   => $imageWorkWidth*$imageWorkHeight,
135          'analyzed' => $i,
136          'time'     => microtime(true)-$time,
137          'pps'      => $i/(microtime(true)-$time),
138        );
139
140        ksort($returned['L']);
141        ksort($returned['A']);
142        ksort($returned['M']);
143        ksort($returned['R']);
144        ksort($returned['G']);
145        ksort($returned['B']);
146
147        foreach($returned as $key => $val)
148        {
149          $m=max($returned[$key]);
150          foreach($returned[$key] as $key2 => $val2)
151          {
152            $returned[$key][$key2]=round($val2/$m,4);
153          }
154        }
155
156        return($returned);
157      }
158      catch (Exception $e)
159      {
160        //echo "ERROR!<br>".print_r($e, true);
161        return(-3);
162      }
163    }
164    else
165    {
166      return(-1);
167    }
168  }
169
170
171  /**
172   * build the histogram and save it in an image file
173   *
174   * @param String $fileName : the histogram filename
175   * @param Array $values : array('L', 'R', 'G', 'B') of values
176   * @param Array $options : array of options for histogram rendering
177   *                'color_bg' : background color
178   *                'color_l'  : color for luminance drawing
179   *                'color_r'  : color for red drawing
180   *                'color_g'  : color for green drawing
181   *                'color_b'  : color for blue drawing
182   *                'color_ticks'  : color for ticks drawing
183   *                'mode_l'   : drawing mode for luminance
184   *                'mode_r'   : drawing mode for luminance
185   *                'mode_g'   : drawing mode for luminance
186   *                'mode_b'   : drawing mode for luminance
187   *                  => modes can takes 'line' or 'bar' or 'surface' or 'none' values
188   *                'mode_ticks_h' : drawing mode for horizontal ticks
189   *                'mode_ticks_v' : drawing mode for vertical ticks
190   *                  => can takes 'none' or 'dot' or 'solid'
191   *                'histo_width' : histogram width
192   *                'histo_height' : histogram height
193   */
194  static function build($fileName, $values, $options=array())
195  {
196    $options=self::checkHistoOptions($options);
197
198    $image=imagecreatetruecolor($options['histo_width'], $options['histo_height']);
199    $options['color_bg']=self::colorAllocate($image, $options['color_bg']);
200    $options['color_v']=self::colorAllocate($image, $options['color_v']);
201    $options['color_r']=self::colorAllocate($image, $options['color_r']);
202    $options['color_g']=self::colorAllocate($image, $options['color_g']);
203    $options['color_b']=self::colorAllocate($image, $options['color_b']);
204
205    imagefilledrectangle($image,0,0,$options['histo_width'], $options['histo_height'], $options['color_bg']);
206
207
208    $histoList=array('v', 'r', 'g', 'b');
209
210
211    foreach($histoList as $histo)
212    {
213      switch($options['mode_'.$histo])
214      {
215        case 'line':
216        case 'surface':
217          $points=array(0,$options['histo_height']);
218          if($histo=='v')
219          {
220            $histoKey=$options['histo_method'];
221          }
222          else
223          {
224            $histoKey=$histo;
225          }
226
227          foreach($values[strtoupper($histoKey)] as $key => $histoValue)
228          {
229            $points[]=$key * $options['histo_width']/255;
230            $points[]=$options['histo_height'] - $histoValue * $options['histo_height'];
231          }
232          $points[]=$options['histo_width'];
233          $points[]=$options['histo_height'];
234
235          if($options['mode_'.$histo]=='line')
236          {
237            imagepolygon($image,$points, count($points)/2, $options['color_'.$histo]);
238          }
239          else
240          {
241            imagefilledpolygon($image,$points, count($points)/2, $options['color_'.$histo]);
242          }
243          break;
244        case 'bar':
245          break;
246      }
247    }
248
249    imagepng($image, $fileName);
250    imagedestroy($image);
251  }
252
253
254  /**
255   *  Calculate the Luminance value from a RGB value
256   *
257   * @param Array $RGB : RGB object
258   * @return Integer : luminance color
259   */
260  static public function RGBtoL($RGB)
261  {
262    return(round($RGB['R']*0.299+$RGB['G']*0.587+$RGB['B']*0.114,0));
263  }
264
265  /**
266   *  Calculate the average grey value from a RGB value
267   *
268   * @param Array $RGB : RGB object
269   * @return Integer : average grey color
270   */
271  static public function RGBtoA($RGB)
272  {
273    return(round(($RGB['R']+$RGB['G']+$RGB['B'])/3,0));
274  }
275
276
277  /**
278   *  Calculate the max value from a RGB value
279   *
280   * @param Array $RGB : RGB object
281   * @return Integer : the max value
282   */
283  static public function RGBtoM($RGB)
284  {
285    return(max($RGB));
286  }
287
288
289  /**
290   *
291   * @param Int $rgb : an integer &hRRGGBB
292   * @return RGB : a RGB object
293   */
294  static public function IntToRGB($rgb)
295  {
296    return(
297      Array(
298        'R' => ($rgb >> 16) & 0xFF,
299        'G' => ($rgb >> 8) & 0xFF,
300        'B' => $rgb & 0xFF
301      )
302    );
303  }
304
305  /**
306   * convert a string like #rrggbb into a RGB array
307   *
308   * @param String $rgb : a #rrggbb string
309   * @return Array
310   */
311  static public function StringToRGB($rgb)
312  {
313    $returned=array(
314      'R' => 0,
315      'G' => 0,
316      'B' => 0
317    );
318
319    if(preg_match_all('/^#([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})$/i', $rgb, $values, PREG_SET_ORDER)>0)
320    {
321      $returned['R']=intval('0x'.$values[0][1],0);
322      $returned['G']=intval('0x'.$values[0][2],0);
323      $returned['B']=intval('0x'.$values[0][3],0);
324    }
325
326    return($returned);
327  }
328
329  /**
330   * convert a RGB array ('R'=>r, 'G'=>g, 'B'=>b ) into integer value
331   *
332   * @param Array $rgb : rgb array
333   * @return Integer
334   */
335  static public function RGBToInt($rgb)
336  {
337    return($rgb['R']*65536 + $rgb['G']*256 + $rgb['B']);
338  }
339
340  /**
341   * convert a RGB array ('R'=>r, 'G'=>g, 'B'=>b ) into string #rrggbb value
342   *
343   * @param Array $rgb : rgb array
344   * @return String
345   */
346  static public function RGBToString($rgb)
347  {
348    return(
349      sprintf('#%02X%02X%02X', $rgb['R'], $rgb['G'], $rgb['B'])
350    );
351  }
352
353  static public function checkHistoOptions($options)
354  {
355    if(!isset($options['color_bg']) or !is_numeric($options['color_bg'])) $options['color_bg']=0xffffff;
356    if(!isset($options['color_v']) or !is_numeric($options['color_v'])) $options['color_v']=0x808080;
357    if(!isset($options['color_r']) or !is_numeric($options['color_r'])) $options['color_r']=0xA00000;
358    if(!isset($options['color_g']) or !is_numeric($options['color_g'])) $options['color_g']=0x00A000;
359    if(!isset($options['color_b']) or !is_numeric($options['color_b'])) $options['color_b']=0x0000A0;
360
361    $modes=array('surface', 'line', 'bar', 'none');
362    if(!isset($options['mode_v']) or !in_array($options['mode_v'], $modes)) $options['mode_v']='surface';
363    if(!isset($options['mode_r']) or !in_array($options['mode_r'], $modes)) $options['mode_r']='line';
364    if(!isset($options['mode_g']) or !in_array($options['mode_g'], $modes)) $options['mode_g']='line';
365    if(!isset($options['mode_b']) or !in_array($options['mode_b'], $modes)) $options['mode_b']='line';
366
367    if(!isset($options['histo_width']) or !is_numeric($options['histo_width']) or $options['histo_width']<=0) $options['histo_width']=256;
368    if(!isset($options['histo_height']) or !is_numeric($options['histo_height']) or $options['histo_height']<=0) $options['histo_height']=100;
369    if(!isset($options['histo_method']) or !in_array($options['histo_method'], array('L', 'A', 'M'))) $options['histo_method']='L';
370
371    return($options);
372  }
373
374
375  static public function colorAllocate($im, $color)
376  {
377    $rgb=self::IntToRGB($color);
378    return(imagecolorallocate($im, $rgb['R'], $rgb['G'], $rgb['B']));
379  }
380
381  static public function colorAllocateA($im, $color, $alpha)
382  {
383    $rgb=self::IntToRGB($color);
384    return(imagecolorallocatealpha($im, $rgb['R'], $rgb['G'], $rgb['B'], $alpha));
385  }
386
387
388}
389
390
391?>
Note: See TracBrowser for help on using the repository browser.