imagetools.php
author Dan
Tue, 23 Dec 2008 20:20:35 -0500
changeset 64 ee64bb096f56
parent 40 bd3372a2afc1
child 73 1f55c324efcf
permissions -rw-r--r--
A few miscellaneous fixes including modifying WebServer to write data in chunks (improved performance and reliability on a slow connection)

<?php

/**
 * Greyhound - real web management for Amarok
 * Copyright (C) 2008 Dan Fuhry
 *
 * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
 *
 * 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 details.
 */

/**
 * Determines an image's filetype based on its signature.
 * @param string Path to image file
 * @return string One of gif, png, or jpg, or false if none of these.
 */

function get_image_filetype($filename)
{
  $filecontents = @file_get_contents($filename);
  if ( empty($filecontents) )
    return false;
  
  if ( substr($filecontents, 0, 8) == "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" )
    return 'png';
  
  if ( substr($filecontents, 0, 6) == 'GIF87a' || substr($filecontents, 0, 6) == 'GIF89a' )
    return 'gif';
  
  if ( substr($filecontents, 0, 2) == "\xFF\xD8" )
    return 'jpg';
  
  return false;
}

/**
 * Scales an image to the specified width and height, and writes the output to the specified
 * file. Will use ImageMagick if present, but if not will attempt to scale with GD. This will
 * always scale images proportionally, unless $preserve_ratio is set to false.
 * 
 * Ported from Enano CMS (which is also my project)
 * 
 * @param string Path to image file
 * @param string Path to output file
 * @param int Image width, in pixels
 * @param int Image height, in pixels
 * @param bool If true, the output file will be deleted if it exists before it is written
 * @param bool If true, preserves the image's aspect ratio (default)
 * @return bool True on success, false on failure
 */

function scale_image($in_file, $out_file, $width = 225, $height = 225, $unlink = false, $preserve_ratio = true)
{
  global $db, $session, $paths, $template, $plugins; // Common objects
  
  if ( !is_int($width) || !is_int($height) )
    return false;
  
  if ( !file_exists($in_file) )
    return false;
  
  if ( preg_match('/["\'\/\\]/', $in_file) || preg_match('/["\'\/\\]/', $out_file) )
    return false;
  
  if ( file_exists($out_file) && !$unlink )
    return false;
  else if ( file_exists($out_file) && $unlink )
    @unlink($out_file);
  if ( file_exists($out_file) )
    // couldn't unlink (delete) the output file
    return false;
    
  $file_ext = substr($in_file, ( strrpos($in_file, '.') + 1));
  switch($file_ext)
  {
    case 'png':
      $func = 'imagecreatefrompng';
      break;
    case 'jpg':
    case 'jpeg':
      $func = 'imagecreatefromjpeg';
      break;
    case 'gif':
      $func = 'imagecreatefromgif';
      break;
    case 'xpm':
      $func = 'imagecreatefromxpm';
      break;
    default:
      return false;
  }
    
  // try to find convert in the PATH
  // FIXME: unix specific (won't work on windows)
  $path = ( isset($_ENV['PATH']) ) ? $_ENV['PATH'] : ( isset($_SERVER['PATH']) ? $_SERVER['PATH'] : '/usr/local/bin:/usr/bin:/bin' );
  $path = explode(':', $path);
  foreach ( $path as $dir )
  {
    if ( file_exists("$dir/convert") && is_executable("$dir/convert") )
    {
      $magick_path = "$dir/convert";
    }
  }
  
  $can_use_magick = isset($magick_path);
  $can_use_gd = (
      function_exists('getimagesize')         &&
      function_exists('imagecreatetruecolor') &&
      function_exists('imagecopyresampled')   &&
      function_exists($func)
    );
  if ( $can_use_magick )
  {
    if ( !preg_match('/^([\/A-z0-9_-]+)$/', $magick_path) )
    {
      // ImageMagick path seems screwy
      return false;
    }
    $op = ( $preserve_ratio ) ? '>' : '!';
    $cmdline = "\"$magick_path\" \"$in_file\" -resize '{$width}x{$height}$op' \"$out_file\"";
    exec($cmdline, $output, $return);
    if ( !file_exists($out_file) )
      return false;
    return true;
  }
  else if ( $can_use_gd )
  {
    @list($width_orig, $height_orig) = @getimagesize($in_file);
    if ( !$width_orig || !$height_orig )
      return false;
    // calculate new width and height
    
    if ( $preserve_ratio )
    {
      $ratio = $width_orig / $height_orig;
      if ( $ratio > 1 )
      {
        // orig. width is greater that height
        $new_width = $width;
        $new_height = round( $width / $ratio );
      }
      else if ( $ratio < 1 )
      {
        // orig. height is greater than width
        $new_width = round( $height / $ratio );
        $new_height = $height;
      }
      else if ( $ratio == 1 )
      {
        $new_width = $width;
        $new_height = $width;
      }
      if ( $new_width > $width_orig || $new_height > $height_orig )
      {
        // Too big for our britches here; set it to only convert the file
        $new_width = $width_orig;
        $new_height = $height_orig;
      }
    }
    else
    {
      $new_width = $width;
      $new_height = $height;
    }
    
    $newimage = @imagecreatetruecolor($new_width, $new_height);
    if ( !$newimage )
      return false;
    $oldimage = @$func($in_file);
    if ( !$oldimage )
      return false;
    
    // Perform scaling
    imagecopyresampled($newimage, $oldimage, 0, 0, 0, 0, $new_width, $new_height, $width_orig, $height_orig);
    
    // Get output format
    $out_ext = substr($out_file, ( strrpos($out_file, '.') + 1));
    switch($out_ext)
    {
      case 'png':
        $outfunc = 'imagepng';
        break;
      case 'jpg':
      case 'jpeg':
        $outfunc = 'imagejpeg';
        break;
      case 'gif':
        $outfunc = 'imagegif';
        break;
      case 'xpm':
        $outfunc = 'imagexpm';
        break;
      default:
        imagedestroy($newimage);
        imagedestroy($oldimage);
        return false;
    }
    
    // Write output
    $outfunc($newimage, $out_file);
    
    // clean up
    imagedestroy($newimage);
    imagedestroy($oldimage);
    
    // done!
    return true;
  }
  if ( file_exists($out_file) )
    return true;
  return false;
}