Fix for RGBa PNG generator

  1. <?php
  2. // $Id$
  3.  
  4. /**
  5.  * @file rgbapng.module
  6.  * @desc This module provides callbacks that generate transparent PNG for CSS backgrounds.
  7.  *
  8.  * DEPENDENCIES imageapi, imageapi_gd
  9.  * USAGE in your theme stylesheets, use rules like this and in this order:
  10.  * selector {
  11.  *   background: url(rgbapng/FF000040);
  12.  *   background: rgba(255,0,0,0.5);
  13.  * }
  14.  * You still need some PNG hack for <IE7 to display PNGs with alpha transparency
  15.  * @link http://leaverou.me/2009/02/bulletproof-cross-browser-rgba-backgrounds/
  16.  */
  17.  
  18. /**
  19.  * Implementation of hook_menu()
  20.  */
  21. function rgbapng_menu() {
  22.   $items = array();
  23. //  If you use system_theme_data() to list themes, you can't ever enable
  24. //  new themes at admin/build/themes. It's one of the ways Drupal is weird.
  25.   $result = db_query("SELECT filename FROM {system} WHERE status = 1 AND type = 'theme'");
  26.   while ($filename = db_result($result)) {
  27.     $dir = dirname($filename);
  28.     $items[$dir .'/rgbapng/%'] = array(
  29.       'title' => 'RGBa PNG',
  30.       'page callback' => 'rgbapng_image',
  31.       'page arguments' => array(count(split('/', $dir)) + 1),
  32.       'access callback' => TRUE,
  33.       'type' => MENU_CALLBACK,
  34.     );
  35.   }
  36.   return $items;
  37. }
  38.  
  39. /*
  40.  * feature taken from
  41.  * http://leaverou.me/2009/02/bulletproof-cross-browser-rgba-backgrounds/
  42.  */
  43. function rgbapng_image($hex) {
  44.   $file = file_create_path() .'/rgbapng/'. $hex .'.png';
  45.   $dir = dirname($file);
  46.   if (!file_check_directory($dir, FILE_CREATE_DIRECTORY) && !mkdir($dir, 0775, true)) {
  47.     watchdog('rgbapng', 'Failed to create rgbapng directory: %dir', array('%dir' => $dir), WATCHDOG_ERROR);
  48.     return false;
  49.   }
  50.   if (is_file($file)) {
  51.     rgbapng_transfer($file);
  52.   }
  53.   $lockfile = file_directory_temp() .'/rgbapng' . basename($file);
  54.   if (file_exists($lockfile)) {
  55.     watchdog('rgbapng', 'RGBa PNG already generating: %dst, Lock file: %tmp.', array('%dst' => $file, '%tmp' => $lockfile), WATCHDOG_NOTICE);
  56.     // 307 Temporary Redirect, to myself. Lets hope the image is done next time around.
  57.     header('Location: '. request_uri(), TRUE, 307);
  58.     exit;
  59.   }
  60.   touch($lockfile);
  61.   // register the shtdown function to clean up lock files. by the time shutdown
  62.   // functions are being called the cwd has changed from document root, to
  63.   // server root so absolute paths must be used for files in shutdown functions.
  64.   register_shutdown_function('file_delete', realpath($lockfile));
  65.  
  66.   list($r, $g, $b, $a) = imageapi_hex2rgba($hex);
  67.  
  68.   $image = new stdClass();
  69.   $image->toolkit = 'imageapi_gd';
  70.   $image->info = array(
  71.     'width' => 1,
  72.     'height' => 1,
  73.     'extension' => 'png',
  74.     'mime_type' => 'image/png',
  75.   );
  76.   $image->resource = @imagecreatetruecolor(1,1)
  77.     or die('Cannot Initialize new GD image stream');
  78.         imagealphablending($image->resource, FALSE);
  79.         imagesavealpha($image->resource, TRUE);
  80.  
  81.         // Allocate our requested color
  82.         $color = imagecolorallocatealpha($image->resource, $r, $g, $b, $a);
  83.  
  84.         // Fill the image with it
  85.         imagefill($image->resource, 0, 0, $color);
  86.   imageapi_image_close($image, $file);
  87.   if (file_exists($file)) {
  88.     rgbapng_transfer($file);
  89.   }
  90.   // Generate an error if image could not generate.
  91.   watchdog('rgbapng', 'Failed generating an image from %hex using RGBa PNG.', array('%hex' => $hex), WATCHDOG_ERROR);
  92.   header("HTTP/1.0 500 Internal Server Error");
  93.   exit;
  94. }
  95.  
  96. /**
  97.  * STOLEN from imagecache_transfer
  98.  * helper function to transfer files from rgbapng. Determines mime type and sets a last modified header.
  99.  * @param $path path to file to be transferred.
  100.  * @return <exit>
  101.  */
  102.  
  103. function rgbapng_transfer($path) {
  104.   $size = getimagesize($path);
  105.   $headers = array('Content-Type: '. mime_header_encode($size['mime']));
  106.  
  107.   if ($fileinfo = stat($path)) {
  108.     $headers[] = 'Content-Length: '. $fileinfo[7];
  109.     _rgbapng_cache_set_cache_headers($fileinfo, $headers);
  110.   }
  111.   file_transfer($path, $headers);
  112.   exit;
  113. }
  114.  
  115. /**
  116.  * STOLEN from _imagecache_cache_set_cache_headers
  117.  * Set file headers that handle "If-Modified-Since" correctly for the
  118.  * given fileinfo. Most code has been taken from drupal_page_cache_header().
  119.  */
  120. function _rgbapng_cache_set_cache_headers($fileinfo, &$headers) {
  121.   // Set default values:
  122.   $last_modified = gmdate('D, d M Y H:i:s', $fileinfo[9]) .' GMT';
  123.   $etag = '"'. md5($last_modified) .'"';
  124.  
  125.   // See if the client has provided the required HTTP headers:
  126.   $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
  127.                         ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE'])
  128.                         : false;
  129.   $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH'])
  130.                     ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])
  131.                     : false;
  132.  
  133.   if ($if_modified_since && $if_none_match
  134.       && $if_none_match == $etag // etag must match
  135.       && $if_modified_since == $last_modified) { // if-modified-since must match
  136.     header('HTTP/1.1 304 Not Modified');
  137.     // All 304 responses must send an etag if the 200 response
  138.     // for the same object contained an etag
  139.     header('Etag: '. $etag);
  140.     // We must also set Last-Modified again, so that we overwrite Drupal's
  141.     // default Last-Modified header with the right one
  142.     header('Last-Modified: '. $last_modified);
  143.     exit;
  144.   }
  145.  
  146.   // Send appropriate response:
  147.   $headers[] = 'Last-Modified: '. $last_modified;
  148.   $headers[] = 'ETag: '. $etag;
  149. }

Submit Fix

Any tags you'd like to associate with your code, delimitered by commas (example: Views, CCK, Module, etc).
Select the syntax highlighting mode to use.