StrangePlanet » Blog

image

[PHP] Bloquer l’embed d’images mais pas le hotlink

26 juin 2011 by Mistic Leave a Comment

Voici un besoin que j’ai eu pour TM-ScreenMania : empêcher les sites et forums d’embarquer les images haute-définition à l’aide des balises HTML < img > mais les autoriser tout de même à faire des liens directs vers ces images.

Toutes les solutions que j’ai pu trouver empêchent le hotlink c’est-à-dire les embeds ET les liens, et se basant sur le référant (HTTP Referrer).

J’ai donc cherché une façon de faire la différence entre les deux côté server. J’ai trouvé la solution dans la variable globale PHP $_SERVER[‘HTTP_ACCEPTED’]. Dans la cas d’un embed ça commence par image/jpeg mais dans le cas de l’image directement affichée (via un lien) ça commence par text/html.

Il n’y a plus qu’a faire un petit script (tms-image.php dans mon cas) qui teste cette valeur :

<?php
$accept = explode(',', $_SERVER['HTTP_ACCEPT']);

if ($accept[0] == 'text/html') 
{
  $pict = file_get_contents($_GET['file']);
} 
else 
{
  $pict = file_get_contents('hotlink.jpg');
}

header("Content-Type:image/jpeg");
echo $pict;
?>

et rediriger les images vers le script avec une redirection .htaccess (dans la galerie les images HD sont stockées dans un sous-dossier pwg_high) :

RewriteEngine on
RewriteRule ^(.*)/pwg_high/(.*)\.jpg$ tms-image.php?file=$1/pwg_high/$2.jpg [L]

Ce code très simple doit être un peu étoffé si on veut qu’il fonctionne avec différents types d’images.
Notez aussi que tel quel il empêche de faire un embed sur son propre site, pour y remédier on peut tester le referrer avant de faire la redirection pour ne pas la faire si on est sur son propre site :

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^http://(www\.)?tm-screenmania.com/.*$ [NC]
RewriteRule ^(.*)/pwg_high/(.*)\.jpg$ tms-image.php?file=$1/pwg_high/$2.jpg [L]
Posted in: Développement, Web Tagged: embed, hotlink, image, php, picture

[PHP] Calcul de la couleur dominante d’une image

22 mai 2011 by Mistic 12 Comments

Jusqu’à maintenant j’utilisais Picasa pour trouver la couleur dominante des images. Le soft utilise le même algorithme que Google Image (logique) et donne de bons résultats à mon sens. Seulement j’avais besoin d’un truc standalone, soit un soft qui s’exécute en ligne de commande, soit directement une fonction (PHP dans mon cas).
Après avoir trouvé diverses fonctions, aucune ne me satisfaisant pleinement, j’ai faut une compilation de tout ça.

Le but est donc de calculer de quelle couleur de référence l’image s’approche le plus. Dans mon cas ma référence est (en RGB) :

$colors = array(
  'red' => array(255,0,0),
  'orange' => array(255,127,0),
  'yellow' => array(255,255,0),
  'green' => array(0,255,0),
  'blue' => array(0,0,255),
  'purple' => array(127,0,255),
  'pink' => array(255,0,255),
  );

…car ce sont les couleurs que donne Picasa, on peut bien sur ajouter n’importe quelle couleur.

Déjà je travaille dans l’espace HSV (Hue-Saturation-Value), ça donne de meilleurs résultats que dans l’espace RGB (Red-Green-Blue).
Ensuite le fonctionnement est somme toute assez simple : il y à un compteur par couleur de base, qu’on incrémente pour chaque pixel de l’inverse de la différence entre la couleur du pixel et la base, différence calculée en norme euclidienne.
Ainsi le compteur le plus haut correspond à la couleur dominante.

Voici donc ma fonction :

<?php
/**
 * Copyright (C) 2011 Damien SOREL (Mistic)
 * http://www.strangeplanet.fr
 * 
 * This function is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */

// conversion RGB -> HSV
function rgb2hsv ($RGB)
{
  $var_R = $RGB[0]/255;
  $var_G = $RGB[1]/255;
  $var_B = $RGB[2]/255;
  $var_Min = min($var_R, $var_G, $var_B);
  $var_Max = max($var_R, $var_G, $var_B);
  $del_Max = $var_Max - $var_Min;
  
  $V = $var_Max;

  if ($del_Max == 0)
  {
    $H = 0;
    $S = 0;  
  }
  else
  {
    $S = $del_Max / $var_Max;
    $del_R = ((($var_Max - $var_R)/6) + ($del_Max/2)) / $del_Max;
    $del_G = ((($var_Max - $var_G)/6) + ($del_Max/2)) / $del_Max;
    $del_B = ((($var_Max - $var_B)/6) + ($del_Max/2)) / $del_Max;
    
    if      ($var_R == $var_Max) $H = $del_B - $del_G;
    else if ($var_G == $var_Max) $H = (1/3) + $del_R - $del_B;
    else if ($var_B == $var_Max) $H = (2/3) + $del_G - $del_R;
    
    if      ($H<0) $H++;
    else if ($H>1) $H--;
  }
  
  return array($H*255, $S*255, $V*255);
}

// norme euclidienne
function distance($col1, $col2)
{
  $distance = 0;
  for($i=0 ; $i<3 ; $i++)
  {
    $diff[$i] = $col1[$i]/255-$col2[$i]/255;
    $distance += $diff[$i]*$diff[$i];
  }
  if ($distance == 0) $distance = 0.01; // pour ne pas avoir l'inverse de 0
  return sqrt($distance);
}

// fonctionne mère
function get_main_color($img, $points, $colors)
{
  $width = imagesx($img);
  $height = imagesy($img);
  $scale = intval(max($width,$height)/$points);
  
  // Pour chaque base on convertir en HSV et on initialise le compteur
  foreach ($colors as $name => $base)
  {
    $results[$name] = 0;
    $colors[$name] = rgb2hsv($base);
  }
  
  $colors_grey = 0; // Compteur pour les pixels gris (R=G=B)
  $pixel_count = 0; // Compteur du nombre total de pixels analysés
      
  for ($j=0; $j<$height; $j+=$scale)
  {
    for ($i=0; $i<$width; $i+=$scale)
    {
      // Couleur du pixel
      $color = imagecolorat($img, $i, $j);
      $r = ($color >> 16) &0xFF;
      $g = ($color >> 8) &0xFF;
      $b = $color &0xFF;
      
      if ($r==$g and $g==$b)
      {
        $colors_grey++;
      }
      else
      {
        // On incrémente le compteur de chaque base 
        // de l'inverse de la distance à la couleur du pixel
        foreach ($colors as $name => $base)
        {
          $color = rgb2hsv(array($r, $g, $b));
          $results[$name] += 1 / distance($color, $base);
        }
      }
      
      $pixel_count++;
    }
  }

  if ($colors_grey == $pixel_count)
  {
    return 'grey';
  }
  else
  {
    asort($results);
    $results = array_keys($results);
    return $results[count($results)-1];
  }
}

?>

Pour l’utiliser il suffit d’appeler la fonction get_main_color et lui fournissant une image, le nombre de points de contrôle (50 donne de bons résultats tout en ne prenant pas trop de temps, ça fait quand même 2500 points pour une image carrée) et le tableau de base.

$img = imagecreatefromjpeg($url);
echo get_main_color($img, 50, $colors);

J’ai fait de nombreux tests bien sur, en voici quelque-uns avec les fonds d’écrans de Windows 7 : http://www.strangeplanet.fr/files/color/
On remarque que sur certaines images Picasa est plus pertinent, sur d’autres c’est ma fonction… on ne peut pas tout avoir !

Posted in: Développement Tagged: couleur, dominante, image, php

Catégories

  • Créations (9)
  • Développement (16)
  • Général (1)
  • Perso (3)
  • Récits (5)
  • Tutoriels (3)
  • Web (8)

Articles récents

  • Use Travis CI & Coveralls for a web frontend library
  • Comment j’ai transformé un téléphone en moniteur système
  • jQuery QueryBuilder
  • [Piwigo] Un carrousel des dernières photos ajoutées
  • [Musique] Tarja: Colours in the Dark

Étiquettes

bateau c++ calcaires carbon chevrolet cité corvette désespoir encodage escalade extension font forever forêt galerie graphique image javascript jquery mer montagne mort musical musique oblivion patch photoshop php piwigo provence qt ruine rêve sexy site web skins tomb raider trackmania ultramon united ville visual voiture windows étranger

Copyright © 2019 StrangePlanet » Blog.

Omega WordPress Theme by ThemeHall

  • Accueil
  • Blog
  • Galerie
  • Projets
  • À-propos