From 7ccc5a6b1b4541a11b858e09cbd8244909d89c92 Mon Sep 17 00:00:00 2001
From: Dries Buytaert <dries@buytaert.net>
Date: Tue, 1 Feb 2005 16:27:43 +0000
Subject: [PATCH] - Patch #16358 by James: added toolkit to enable better image
 handling.  The avatar code and the upload module have been updated to take
 advantage of the new image API.

There are 5 main functions that modules may now utilize to handle images:

* image_get_info() - this function checks a file.  If it exists and is a valid image file, it will return an array containing things like the pixel dimensions of the image, plus the 'type' and common extension.
* image_scale - resizes a given image to fit within a given width / height dimensions, while maintaining aspect ratio (not distorting the image).  This function can be used to generate thumbnails, or ensure a maximum resolution, etc.
* image_resize - similar to image_scale (but will not respect aspect ratio - may well distort the image).
* image_rotate - rotate an image by X degrees
* image_crop - crops an image to a given rectangle (defined as top-left x/y coordinates plus a width & height of the rectangle).

Contribution modules will now be able to rely on these base manipulation functions to offer additional functionality (such as image nodes, photo galleries, advanced image manipulation, etc).
---
 CHANGELOG.txt                |   1 +
 includes/common.inc          |   1 +
 includes/image.inc           | 292 +++++++++++++++++++++++++++++++++++
 modules/system.module        |  13 +-
 modules/system/system.module |  13 +-
 modules/upload.module        |  28 +++-
 modules/upload/upload.module |  28 +++-
 modules/user.module          |  37 ++---
 modules/user/user.module     |  37 ++---
 9 files changed, 388 insertions(+), 62 deletions(-)
 create mode 100644 includes/image.inc

diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 1adf7c5ea549..b829d56c9d69 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -23,6 +23,7 @@ Drupal x.x.x, xxxx-xx-xx
     * added a simple contact module that allows users to contact each other using e-mail.
 - multi-site configuration:
     * made it possible to run multiple sites from a single code base.
+- added an image API: enables better image handling.
 - block system:
     * extended the block visibility settings.
 - theme system:
diff --git a/includes/common.inc b/includes/common.inc
index 8a45ff94a6a1..0ace8d84b39f 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -1806,6 +1806,7 @@ function drupal_get_path($type, $name) {
 include_once 'includes/tablesort.inc';
 include_once 'includes/file.inc';
 include_once 'includes/xmlrpc.inc';
+include_once 'includes/image.inc';
 
 // Set the Drupal custom error handler.
 set_error_handler('error_handler');
diff --git a/includes/image.inc b/includes/image.inc
new file mode 100644
index 000000000000..b485496d7e7a
--- /dev/null
+++ b/includes/image.inc
@@ -0,0 +1,292 @@
+<?php
+// $Id$
+
+/**
+ * Return a list of available toolkits.
+ *
+ * @return An array of toolkit name => descriptive title
+ */
+function image_get_available_toolkits() {
+  $toolkits = file_scan_directory('includes', 'image\..*\.inc$');
+
+  $output = array();
+  foreach ($toolkits as $file => $toolkit) {
+    include_once($file);
+    $function = str_replace('.', '_', $toolkit->name) . '_info';
+    if (function_exists($function)) {
+      $info = $function();
+      $output[$info['name']] = $info['title'];
+    }
+  }
+  $output['gd'] = t('Built-in GD Toolkit');
+  return $output;
+}
+
+/**
+ * Retrieve the name of the currently used toolkit.
+ *
+ * @return String containing the name of the toolkit.
+ */
+function image_get_toolkit() {
+  static $toolkit;
+  if (!$toolkit) {
+    $toolkit = variable_get('image_toolkit', 'gd');
+    if ($toolkit != 'gd') {
+      include_once 'includes/image.'.$toolkit.'.inc';
+    }
+  }
+
+  return $toolkit;
+}
+
+/**
+ * Invokes the given method using the currently selected toolkit.
+ *
+ * @param $method A string containing the method to invoke.
+ * @param $params An optional array of parameters to pass to the toolkit method
+ *
+ * @return Mixed values (typically Boolean for successful operation)
+ */
+function image_toolkit_invoke($method, $params = array()) {
+  $toolkit = image_get_toolkit();
+
+  $function = 'image_' . $toolkit . '_'. $method;
+  if (function_exists($function)) {
+    return call_user_func_array($function, $params);
+  }
+  else {
+    drupal_set_message(t('%method is not supported by %toolkit.', array('%method' => "<em>$method</em>", '%toolkit' => "<em>$toolkit</em>")));
+  }
+}
+
+
+/**
+ * Get details about an image.
+ *
+ * @return array containing information about the image
+ *      'width': image's width in pixels
+ *      'height': image's height in pixels
+ *      'extension': commonly used extension for the image
+ *      'mime_type': image's MIME type ('image/jpeg', 'image/gif', etc.)
+ */
+function image_get_info($file) {
+  if (!file_exists($file)) {
+    return false;
+  }
+
+  $details = false;
+  $data = @getimagesize($file);
+
+  if (is_array($data)) {
+    $extensions = array('1' => 'gif', '2' => 'jpg', '3' => 'png');
+    $extension = array_key_exists($data[2], $extensions) ?  $extensions[$data[2]] : '';
+    $details = array('width'     => $data[0],
+        'height'    => $data[1],
+        'extension' => $extension,
+        'mime_type' => $data['mime']);
+  }
+
+  return $details;
+}
+
+/**
+ * Scales an image to the given width and height while maintaining aspect
+ * ratio.
+ *
+ * @param $source         The filepath of the source image
+ * @param $destination    The file path of the destination image
+ * @param $width          The target width
+ * @param $height         The target height
+ *
+ * @return True or false, based on success
+ */
+function image_scale($source, $destination, $width, $height) {
+  $info = image_get_info($source);
+
+  // don't scale up
+  if ($width > $info['width'] && $height > $info['height']) {
+    return false;
+  }
+
+  $aspect = $info['height'] / $info['width'];
+  if ($aspect < $height / $width) {
+    $width = (int)min($width, $info['width']);
+    $height = (int)round($width * $aspect);
+  } else {
+    $height = (int)min($height, $info['height']);
+    $width = (int)round($height / $aspect);
+  }
+
+  return image_toolkit_invoke('resize', array($source, $destination, $width, $height));
+}
+
+/**
+ * Resize an image to the given dimensions (ignoring aspect ratio).
+ *
+ * @param $source        The filepath of the source image.
+ * @param $destination   The file path of the destination image.
+ * @param $width         The target width.
+ * @param $height        The target height.
+ */
+function image_resize($source, $destination, $width, $height) {
+  return image_toolkit_invoke('resize', array($source, $destination, $width, $height));
+}
+
+/**
+ * Rotate an image by the given number of degrees.
+ *
+ * @param $source  The filepath of the source image
+ * @param $destination    The file path of the destination image
+ * @param $degrees The number of (clockwise) degrees to rotate the image
+ */
+function image_rotate($source, $destination, $degrees) {
+  return image_toolkit_invoke('rotate', array($source, $destination, $degrees));
+}
+
+/**
+ * Crop an image to the rectangle specified by the given rectangle.
+ *
+ * @param $source        The filepath of the source image
+ * @param $destination   The file path of the destination image
+ * @param $x             The top left co-ordinate of the crop area (x axis value)
+ * @param $y             The top left co-ordinate of the crop area (y axis value)
+ * @param $width         The target width
+ * @param $height        The target height
+ */
+function image_crop($source, $destination, $x, $y, $width, $height) {
+  return image_toolkit_invoke('crop', array($source, $destination, $x, $y, $width, $height));
+}
+
+/**
+ * GD Toolkit functions
+ */
+
+/**
+ * Verify GD settings (that the extension is actually installed).
+ */
+function image_gd_settings() {
+  if (!extension_loaded('gd')) {
+    drupal_set_message(t('Unable to load the GD toolkit'), 'error');
+  }
+}
+
+/**
+ * Scale an image to the specified size using GD.
+ */
+function image_gd_resize($source, $destination, $width, $height) {
+  if (!file_exists($source)) {
+    return false;
+  }
+
+  $info = image_get_info($source);
+  if (!$info) {
+    return false;
+  }
+
+  $im = image_gd_open($source, $info['extension']);
+  if (!$im) {
+    return false;
+  }
+
+  // GD1 doesn't have true color
+  if (function_exists('imageCreateTrueColor')) {
+    $res = imageCreateTrueColor($width, $height);
+  }
+  else {
+    $res = imageCreate($width, $height);
+  }
+
+  // GD1 doesn't have copyResampled
+  if (function_exists('imageCopyResampled')) {
+    imageCopyResampled($res, $im, 0, 0, 0, 0, $width, $height, $info['width'], $info['height']);
+  }
+  else {
+    imageCopyResized($res, $im, 0, 0, 0, 0, $width, $height, $info['width'], $info['height']);
+  }
+  $result = image_gd_close($res, $destination, $info['extension']);
+
+  imageDestroy($res);
+  imageDestroy($im);
+
+  return $result;
+}
+
+/**
+ * Rotate an image the given number of degrees.
+ */
+function image_gd_rotate($source, $destination, $degrees, $bg_color = 0) {
+  if (!function_exists('imageRotate')) {
+    return false;
+  }
+
+  $info = image_get_info($source);
+  if (!$info) {
+    return false;
+  }
+
+  $im = image_gd_open($source, $info['extension']);
+  if (!$im) {
+    return false;
+  }
+
+  $res = imageRotate($im, $degrees, $bg_color);
+
+  $result = image_gd_close($res, $destination, $info['extension']);
+
+  return $result;
+}
+
+/**
+ * Crop an image using the GD toolkit.
+ */
+function image_gd_crop($source, $destination, $x, $y, $width, $height) {
+  $info = image_get_info($source);
+  if (!$info) {
+    return false;
+  }
+
+  $im = image_gd_open($source, $info['extension']);
+
+  // GD1 doesn't have true color
+  if (function_exists('imageCreateTrueColor')) {
+    $res = imageCreateTrueColor($width, $height);
+  }
+  else {
+    $res = imageCreate($width, $height);
+  }
+
+  imageCopy($im, $res, 0, 0, $x, $y, $width, $height);
+
+  $result = image_gd_close($res, $destination, $info['extension']);
+
+  imageDestroy($res);
+  imageDestroy($im);
+
+  return $result;
+}
+
+/**
+ * GD helper function to create an image resource from a file.
+ */
+function image_gd_open($file, $extension) {
+  $extension = str_replace('jpg', 'jpeg', $extension);
+  $open_func = 'imageCreateFrom'. $extension;
+  if (!function_exists($open_func)) {
+    return false;
+  }
+  return $open_func($file);
+}
+
+/**
+ * GD helper to write an image resource to a destination file.
+ */
+function image_gd_close($res, $destination, $extension) {
+  $extension = str_replace('jpg', 'jpeg', $extension);
+  $close_func = 'image'. $extension;
+  if (!function_exists($close_func)) {
+    return false;
+  }
+  return $close_func($res, $destination);
+}
+
+?>
diff --git a/modules/system.module b/modules/system.module
index b0dcfb443f43..e42fd19d8ad7 100644
--- a/modules/system.module
+++ b/modules/system.module
@@ -239,6 +239,17 @@ function system_view_general() {
   $group .= form_radios(t('Download method'), 'file_downloads', variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC), array(FILE_DOWNLOADS_PUBLIC => t('Public - files are available using http directly.'), FILE_DOWNLOADS_PRIVATE => t('Private - files are transferred by Drupal.')), t('If you want any sort of access control on the downloading of files, this needs to be set to <em>private</em>. You can change this at any time, however all download URLs will change and there may be unexpected problems so it is not recommended.'));
   $output .= form_group(t('File system settings'), $group);
 
+  // image handling:
+  $group = '';
+  $toolkits_available = image_get_available_toolkits();
+  if (count($toolkits_available) > 1) {
+    $group .= form_radios(t('Select an image processing toolkit'), 'image_toolkit', variable_get('image_toolkit', image_get_toolkit()), $toolkits_available);
+  }
+  $group .= image_toolkit_invoke('settings');
+  if ($group) {
+    $output .= form_group(t('Image handling'), $group);
+  }
+
   // date settings:
   $zones = _system_zonelist();
 
@@ -612,7 +623,7 @@ function system_theme_settings() {
 
   // Check for a new uploaded logo, and use that instead.
   if ($file = file_check_upload('logo_upload')) {
-    if (in_array($file->filemime, array('image/jpeg', 'image/gif', 'image/png'))) {
+    if ($info = image_get_info($file->filepath)) {
       $parts = pathinfo($file->filename);
       $filename = ($key) ? str_replace('/', '_', $key) . '_logo.' . $parts['extension'] : 'logo.' . $parts['extension'];
 
diff --git a/modules/system/system.module b/modules/system/system.module
index b0dcfb443f43..e42fd19d8ad7 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -239,6 +239,17 @@ function system_view_general() {
   $group .= form_radios(t('Download method'), 'file_downloads', variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC), array(FILE_DOWNLOADS_PUBLIC => t('Public - files are available using http directly.'), FILE_DOWNLOADS_PRIVATE => t('Private - files are transferred by Drupal.')), t('If you want any sort of access control on the downloading of files, this needs to be set to <em>private</em>. You can change this at any time, however all download URLs will change and there may be unexpected problems so it is not recommended.'));
   $output .= form_group(t('File system settings'), $group);
 
+  // image handling:
+  $group = '';
+  $toolkits_available = image_get_available_toolkits();
+  if (count($toolkits_available) > 1) {
+    $group .= form_radios(t('Select an image processing toolkit'), 'image_toolkit', variable_get('image_toolkit', image_get_toolkit()), $toolkits_available);
+  }
+  $group .= image_toolkit_invoke('settings');
+  if ($group) {
+    $output .= form_group(t('Image handling'), $group);
+  }
+
   // date settings:
   $zones = _system_zonelist();
 
@@ -612,7 +623,7 @@ function system_theme_settings() {
 
   // Check for a new uploaded logo, and use that instead.
   if ($file = file_check_upload('logo_upload')) {
-    if (in_array($file->filemime, array('image/jpeg', 'image/gif', 'image/png'))) {
+    if ($info = image_get_info($file->filepath)) {
       $parts = pathinfo($file->filename);
       $filename = ($key) ? str_replace('/', '_', $key) . '_logo.' . $parts['extension'] : 'logo.' . $parts['extension'];
 
diff --git a/modules/upload.module b/modules/upload.module
index c1fc086416fa..559b46d87b6f 100644
--- a/modules/upload.module
+++ b/modules/upload.module
@@ -63,7 +63,8 @@ function upload_menu($may_cache) {
 function upload_admin() {
   system_settings_save();
 
-  $group .= form_textfield(t('Maximum total file size'), 'upload_maxsize_total', variable_get('upload_maxsize_total', 0), 5, 5, t('The maximum size of a file a user can upload in megabytes. Enter 0 for unlimited.'));
+  $group .= form_textfield(t('Maximum total file size'), 'upload_maxsize_total', variable_get('upload_maxsize_total', 0), 10, 10, t('The maximum size of a file a user can upload in megabytes. Enter 0 for unlimited.'));
+  $group .= form_textfield(t('Maximum resolution for uploaded images'), 'upload_max_resolution', variable_get('upload_max_resolution', 0), 10, 10, t('The maximum allowed image size expressed as WIDTHxHEIGHT (e.g. 640x480). Set to 0 for no restriction.'));
 
   $output = form_group(t('General settings'), $group);
 
@@ -138,7 +139,9 @@ function upload_nodeapi(&$node, $op, $arg) {
       if (($file = file_check_upload('upload')) && user_access('upload files')) {
         global $user;
 
-        $max_size = variable_get("upload_maxsize_total", 0);
+        $file = _upload_image($file);
+
+        $maxsize = variable_get("upload_maxsize_total", 0);
         $total_size = upload_count_size() + $filesize;
         $total_usersize = upload_count_size($user->uid) + $filesize;
 
@@ -371,4 +374,25 @@ function upload_load($node) {
   return $files;
 }
 
+/**
+ * Check an upload, if it is an image, make sure it fits within the
+ * maximum dimensions allowed.
+ */
+function _upload_image($file) {
+  $info = image_get_info($file->filepath);
+
+  if ($info) {
+    list($width, $height) = explode('x', variable_get('upload_max_resolution', 0));
+    if ($width && $height) {
+      $result = image_scale($file->filepath, $file->filepath, $width, $height);
+      if ($result) {
+        $file->filesize = filesize($file->filepath);
+        drupal_set_message(t('Your image was resized to fit within the maximum allowed resolution of %resolution pixels.', array('%resolution' => variable_get('upload_max_resolution', 0))));
+      }
+    }
+  }
+
+  return $file;
+}
+
 ?>
diff --git a/modules/upload/upload.module b/modules/upload/upload.module
index c1fc086416fa..559b46d87b6f 100644
--- a/modules/upload/upload.module
+++ b/modules/upload/upload.module
@@ -63,7 +63,8 @@ function upload_menu($may_cache) {
 function upload_admin() {
   system_settings_save();
 
-  $group .= form_textfield(t('Maximum total file size'), 'upload_maxsize_total', variable_get('upload_maxsize_total', 0), 5, 5, t('The maximum size of a file a user can upload in megabytes. Enter 0 for unlimited.'));
+  $group .= form_textfield(t('Maximum total file size'), 'upload_maxsize_total', variable_get('upload_maxsize_total', 0), 10, 10, t('The maximum size of a file a user can upload in megabytes. Enter 0 for unlimited.'));
+  $group .= form_textfield(t('Maximum resolution for uploaded images'), 'upload_max_resolution', variable_get('upload_max_resolution', 0), 10, 10, t('The maximum allowed image size expressed as WIDTHxHEIGHT (e.g. 640x480). Set to 0 for no restriction.'));
 
   $output = form_group(t('General settings'), $group);
 
@@ -138,7 +139,9 @@ function upload_nodeapi(&$node, $op, $arg) {
       if (($file = file_check_upload('upload')) && user_access('upload files')) {
         global $user;
 
-        $max_size = variable_get("upload_maxsize_total", 0);
+        $file = _upload_image($file);
+
+        $maxsize = variable_get("upload_maxsize_total", 0);
         $total_size = upload_count_size() + $filesize;
         $total_usersize = upload_count_size($user->uid) + $filesize;
 
@@ -371,4 +374,25 @@ function upload_load($node) {
   return $files;
 }
 
+/**
+ * Check an upload, if it is an image, make sure it fits within the
+ * maximum dimensions allowed.
+ */
+function _upload_image($file) {
+  $info = image_get_info($file->filepath);
+
+  if ($info) {
+    list($width, $height) = explode('x', variable_get('upload_max_resolution', 0));
+    if ($width && $height) {
+      $result = image_scale($file->filepath, $file->filepath, $width, $height);
+      if ($result) {
+        $file->filesize = filesize($file->filepath);
+        drupal_set_message(t('Your image was resized to fit within the maximum allowed resolution of %resolution pixels.', array('%resolution' => variable_get('upload_max_resolution', 0))));
+      }
+    }
+  }
+
+  return $file;
+}
+
 ?>
diff --git a/modules/user.module b/modules/user.module
index d896367bce42..785d72b80b8a 100644
--- a/modules/user.module
+++ b/modules/user.module
@@ -227,20 +227,19 @@ function user_validate_picture($file, &$edit, $user) {
 
   // Check that uploaded file is an image, with a maximum file size
   // and maximum height/width.
-  $extension = strtolower(strrchr($file->filename, '.'));
-  $size = @getimagesize($file->filepath);
+  $info = image_get_info($file->filepath);
   list($maxwidth, $maxheight) = explode('x', variable_get('user_picture_dimensions', '85x85'));
 
-  if ((!in_array($size[2], array(1, 2, 3))) || (!in_array($extension, array('.gif', '.jpg', '.png', '.jpeg')))) {
+  if (!$info || !$info['extension']) {
     form_set_error('picture', t('The uploaded file was not an image.'));
   }
-  else if ($file->size > (variable_get('user_picture_file_size', '30') * 1000)) {
-    form_set_error('picture', t('The uploaded image is too large; the maximum file size is %size kB.', array('%size' => variable_get('user_picture_file_size', '30'))));
-  }
-  else if ($size[0] > $maxwidth || $size[1] > $maxheight) {
+  else if (!image_scale($file->filepath, $file->filepath, $maxwidth, $maxheight)) {
     form_set_error('picture', t('The uploaded image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => variable_get('user_picture_dimensions', '85x85'))));
   }
-  else if ($file = file_save_upload('picture', variable_get('user_picture_path', 'pictures') .'/picture-'. $user->uid . $extension, 1)) {
+  else if (filesize($file->filepath) > (variable_get('user_picture_file_size', '30') * 1000)) {
+    form_set_error('picture', t('The uploaded image is too large; the maximum file size is %size kB.', array('%size' => variable_get('user_picture_file_size', '30'))));
+  }
+  else if ($file = file_save_upload('picture', variable_get('user_picture_path', 'pictures') .'/picture-'. $user->uid . '.' . $info['extension'], 1)) {
     $edit['picture'] = $file->filepath;
   }
   else {
@@ -403,26 +402,8 @@ function user_perm() {
  */
 function user_file_download($file) {
   if (strpos($file, variable_get('user_picture_path', 'pictures') .'/picture-') === 0) {
-    list($width, $height, $type, $attr) = @getimagesize(file_create_path($file));
-    $types = array(
-      IMAGETYPE_GIF => 'image/gif',
-      IMAGETYPE_JPEG => 'image/jpeg',
-      IMAGETYPE_PNG => 'image/png',
-      IMAGETYPE_SWF => 'application/x-shockwave-flash',
-      IMAGETYPE_PSD => 'image/psd',
-      IMAGETYPE_BMP => 'image/bmp',
-      IMAGETYPE_TIFF_II => 'image/tiff',
-      IMAGETYPE_TIFF_MM  => 'image/tiff',
-      IMAGETYPE_JPC => 'application/octet-stream',
-      IMAGETYPE_JP2 => 'image/jp2',
-      IMAGETYPE_JPX => 'application/octet-stream',
-      IMAGETYPE_JB2 => 'application/octet-stream',
-      IMAGETYPE_SWC => 'application/x-shockwave-flash',
-      IMAGETYPE_IFF => 'image/iff',
-      IMAGETYPE_WBMP => 'image/vnd.wap.wbmp',
-      IMAGETYPE_XBM => 'image/xbm'
-    );
-    return array('Content-type: '. $types[$type]);
+    $info = image_get_info(file_create_path($file));
+    return array('Content-type: '. $info['mime_type']);
   }
 }
 
diff --git a/modules/user/user.module b/modules/user/user.module
index d896367bce42..785d72b80b8a 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -227,20 +227,19 @@ function user_validate_picture($file, &$edit, $user) {
 
   // Check that uploaded file is an image, with a maximum file size
   // and maximum height/width.
-  $extension = strtolower(strrchr($file->filename, '.'));
-  $size = @getimagesize($file->filepath);
+  $info = image_get_info($file->filepath);
   list($maxwidth, $maxheight) = explode('x', variable_get('user_picture_dimensions', '85x85'));
 
-  if ((!in_array($size[2], array(1, 2, 3))) || (!in_array($extension, array('.gif', '.jpg', '.png', '.jpeg')))) {
+  if (!$info || !$info['extension']) {
     form_set_error('picture', t('The uploaded file was not an image.'));
   }
-  else if ($file->size > (variable_get('user_picture_file_size', '30') * 1000)) {
-    form_set_error('picture', t('The uploaded image is too large; the maximum file size is %size kB.', array('%size' => variable_get('user_picture_file_size', '30'))));
-  }
-  else if ($size[0] > $maxwidth || $size[1] > $maxheight) {
+  else if (!image_scale($file->filepath, $file->filepath, $maxwidth, $maxheight)) {
     form_set_error('picture', t('The uploaded image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => variable_get('user_picture_dimensions', '85x85'))));
   }
-  else if ($file = file_save_upload('picture', variable_get('user_picture_path', 'pictures') .'/picture-'. $user->uid . $extension, 1)) {
+  else if (filesize($file->filepath) > (variable_get('user_picture_file_size', '30') * 1000)) {
+    form_set_error('picture', t('The uploaded image is too large; the maximum file size is %size kB.', array('%size' => variable_get('user_picture_file_size', '30'))));
+  }
+  else if ($file = file_save_upload('picture', variable_get('user_picture_path', 'pictures') .'/picture-'. $user->uid . '.' . $info['extension'], 1)) {
     $edit['picture'] = $file->filepath;
   }
   else {
@@ -403,26 +402,8 @@ function user_perm() {
  */
 function user_file_download($file) {
   if (strpos($file, variable_get('user_picture_path', 'pictures') .'/picture-') === 0) {
-    list($width, $height, $type, $attr) = @getimagesize(file_create_path($file));
-    $types = array(
-      IMAGETYPE_GIF => 'image/gif',
-      IMAGETYPE_JPEG => 'image/jpeg',
-      IMAGETYPE_PNG => 'image/png',
-      IMAGETYPE_SWF => 'application/x-shockwave-flash',
-      IMAGETYPE_PSD => 'image/psd',
-      IMAGETYPE_BMP => 'image/bmp',
-      IMAGETYPE_TIFF_II => 'image/tiff',
-      IMAGETYPE_TIFF_MM  => 'image/tiff',
-      IMAGETYPE_JPC => 'application/octet-stream',
-      IMAGETYPE_JP2 => 'image/jp2',
-      IMAGETYPE_JPX => 'application/octet-stream',
-      IMAGETYPE_JB2 => 'application/octet-stream',
-      IMAGETYPE_SWC => 'application/x-shockwave-flash',
-      IMAGETYPE_IFF => 'image/iff',
-      IMAGETYPE_WBMP => 'image/vnd.wap.wbmp',
-      IMAGETYPE_XBM => 'image/xbm'
-    );
-    return array('Content-type: '. $types[$type]);
+    $info = image_get_info(file_create_path($file));
+    return array('Content-type: '. $info['mime_type']);
   }
 }
 
-- 
GitLab