Skip to content

Instantly share code, notes, and snippets.

@pqina
Last active June 29, 2023 18:13
Show Gist options
  • Save pqina/7a42bf0833d988dd81d3c9438009da21 to your computer and use it in GitHub Desktop.
Save pqina/7a42bf0833d988dd81d3c9438009da21 to your computer and use it in GitHub Desktop.
Create thumbnails with PHP
<?
// Link image type to correct image loader and saver
// - makes it easier to add additional types later on
// - makes the function easier to read
const IMAGE_HANDLERS = [
IMAGETYPE_JPEG => [
'load' => 'imagecreatefromjpeg',
'save' => 'imagejpeg',
'quality' => 100
],
IMAGETYPE_PNG => [
'load' => 'imagecreatefrompng',
'save' => 'imagepng',
'quality' => 0
],
IMAGETYPE_GIF => [
'load' => 'imagecreatefromgif',
'save' => 'imagegif'
]
];
/**
* @param $src - a valid file location
* @param $dest - a valid file target
* @param $targetWidth - desired output width
* @param $targetHeight - desired output height or null
*/
function createThumbnail($src, $dest, $targetWidth, $targetHeight = null) {
// 1. Load the image from the given $src
// - see if the file actually exists
// - check if it's of a valid image type
// - load the image resource
// get the type of the image
// we need the type to determine the correct loader
$type = exif_imagetype($src);
// if no valid type or no handler found -> exit
if (!$type || !IMAGE_HANDLERS[$type]) {
return null;
}
// load the image with the correct loader
$image = call_user_func(IMAGE_HANDLERS[$type]['load'], $src);
// no image found at supplied location -> exit
if (!$image) {
return null;
}
// 2. Create a thumbnail and resize the loaded $image
// - get the image dimensions
// - define the output size appropriately
// - create a thumbnail based on that size
// - set alpha transparency for GIFs and PNGs
// - draw the final thumbnail
// get original image width and height
$width = imagesx($image);
$height = imagesy($image);
// maintain aspect ratio when no height set
if ($targetHeight == null) {
// get width to height ratio
$ratio = $width / $height;
// if is portrait
// use ratio to scale height to fit in square
if ($width > $height) {
$targetHeight = floor($targetWidth / $ratio);
}
// if is landscape
// use ratio to scale width to fit in square
else {
$targetHeight = $targetWidth;
$targetWidth = floor($targetWidth * $ratio);
}
}
// create duplicate image based on calculated target size
$thumbnail = imagecreatetruecolor($targetWidth, $targetHeight);
// set transparency options for GIFs and PNGs
if ($type == IMAGETYPE_GIF || $type == IMAGETYPE_PNG) {
// make image transparent
imagecolortransparent(
$thumbnail,
imagecolorallocate($thumbnail, 0, 0, 0)
);
// additional settings for PNGs
if ($type == IMAGETYPE_PNG) {
imagealphablending($thumbnail, false);
imagesavealpha($thumbnail, true);
}
}
// copy entire source image to duplicate image and resize
imagecopyresampled(
$thumbnail,
$image,
0, 0, 0, 0,
$targetWidth, $targetHeight,
$width, $height
);
// 3. Save the $thumbnail to disk
// - call the correct save method
// - set the correct quality level
// save the duplicate version of the image to disk
return call_user_func(
IMAGE_HANDLERS[$type]['save'],
$thumbnail,
$dest,
IMAGE_HANDLERS[$type]['quality']
);
}
@otahirs
Copy link

otahirs commented Feb 16, 2019

the imagegif() function does not have third parameter so after calling call_user_func() on a gif img an error occurs invalid index "quality"

@Ihnatenko
Copy link

After reducing the image, its size in bytes only grows.

@SlimenTN
Copy link

it works !! awesome .

@manishram
Copy link

If you are trying to make a thumbnail of "gif" image and you are getting invalid index "quality", then go to line 17 and replace
IMAGETYPE_GIF => [ 'load' => 'imagecreatefromgif', 'save' => 'imagegif' ]

with

IMAGETYPE_GIF => [ 'load' => 'imagecreatefromgif', 'save' => 'imagegif', 'quality' => 0 ]

@maxrys
Copy link

maxrys commented Sep 21, 2019

Example from effcore CMS/CMF (/system/module_core/backend/core.php):

namespace effcore {
          abstract class core {

  static function thumbnail_create($src_path, $dst_path, $dst_w = 100, $result_format = null) {
    $type = @exif_imagetype($src_path);
    if ($type !== false) {
      if ($type == IMAGETYPE_GIF  && function_exists('imagecreatefromgif' )) $src_resource = @imagecreatefromgif ($src_path);
      if ($type == IMAGETYPE_JPEG && function_exists('imagecreatefromjpeg')) $src_resource = @imagecreatefromjpeg($src_path);
      if ($type == IMAGETYPE_PNG  && function_exists('imagecreatefrompng' )) $src_resource = @imagecreatefrompng ($src_path);
      if (isset($src_resource) &&
                $src_resource) {
        $src_w = imagesx($src_resource);
        $src_h = imagesy($src_resource);
        $dst_h = (int)($src_h / ($src_w / $dst_w));
        $dst_resource = @imagecreatetruecolor($dst_w, $dst_h);
        @imagecolortransparent($dst_resource, imagecolorallocate($dst_resource, 0, 0, 0));
        @imagealphablending   ($dst_resource, $type == IMAGETYPE_GIF);
        @imagesavealpha       ($dst_resource, true);
        if ($dst_resource) {
          @imagecopyresampled($dst_resource, $src_resource, 0, 0, 0, 0, $dst_w, $dst_h, $src_w, $src_h);
          if ((($type == IMAGETYPE_PNG  && $result_format == null) || $result_format == 'png' ) && function_exists('imagepng' )) $result = @imagepng ($dst_resource, $dst_path.'.png' );
          if ((($type == IMAGETYPE_JPEG && $result_format == null) || $result_format == 'jpeg') && function_exists('imagejpeg')) $result = @imagejpeg($dst_resource, $dst_path.'.jpeg');
          if ((($type == IMAGETYPE_GIF  && $result_format == null) || $result_format == 'gif' ) && function_exists('imagegif' )) $result = @imagegif ($dst_resource, $dst_path.'.gif' );
          @imagedestroy($dst_resource);
          return $result ?? null;
        }
      }
    }
  }

 }}

Usage:

  core::thumbnail_create('/some_file.gif', '/some_file-thumb');
  core::thumbnail_create('/some_file.png', '/some_file-thumb');
  core::thumbnail_create('/some_file.jpg', '/some_file-thumb');

@PolliSoft
Copy link

PolliSoft commented Nov 20, 2019

Thanks a lot for this!
On my page (https://www.pollisoft.se), is use the same thumbnail size for all image size and aspect ratios. With the following change/addition (the else statement) to your script, I avoided thumbnail image distortion when sourceRatio doesn't equal targetRatio. Feel free to include if you want.

`// maintain aspect ratio when no height set
if ($targetHeight == null) {

	$startX = 0;
	$startY = 0;
	$src_w = width;
	$src_h = height;
	
    // get width to height ratio
    $ratio = $width / $height;

    // if is portrait
    // use ratio to scale height to fit in square
    if ($width > $height) {
        $targetHeight = floor($targetWidth / $ratio);
    }
    // if is landscape
    // use ratio to scale width to fit in square
    else {
        $targetHeight = $targetWidth;
        $targetWidth = floor($targetWidth * $ratio);
    }
} else {
	// Calculate starting positions and copy area 
	// to not distort the thumbnail image ratio.
	// get width to height ratio
	$ratio = $width / $height;
	$targetRatio = $targetWidth / $targetHeight;
	$combinedRatio = $ratio / $targetRatio;

	// Cut X wise in source to avoid thumb image distortion
	if ($combinedRatio >= 1) {
		$thumbRatio = $height / $targetHeight;
		$startX = ($width - ($thumbRatio * $targetWidth)) / 2;
		$src_w = ($thumbRatio * $targetWidth);
		$startY = 0;
		$src_h = $height;
	}
	// Cut Y wise in source to avoid thumb image distortion
	else {
		$thumbRatio = $width / $targetWidth;
		$startY = ($height - ($thumbRatio * $targetHeight)) / 2;
		$src_h = ($thumbRatio * $targetHeight);
		$startX = 0;
		$src_w = $width;
	}
}`

@JoomlaTema
Copy link

Hi
I am getting error for gif images : imagegif() expects at most 2 arguments, 3 given
Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment