Image Resizing Script required - a better one...

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Image Resizing Script required - a better one...

Post by simonmlewis »

Oh that's a pain!
That source set I think is all part of the function.
But yes I suppose it could. Have to think about how. But odd for it not to do it anyway.
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Image Resizing Script required - a better one...

Post by simonmlewis »

I suppose in here I can add a third sizing, but NOT to resize, only to VIEW.
But how do I incorporate that, without asking it to use a $suffix. So whereas the others have the _475 etc, the 2560 would just use the default original.

Code: Select all

<?php
require_once (dirname(__DIR__). '/vendor/autoload.php');
// Returns required quality settings for Imagine based on image's extension
function getImageOptions($extension)
{
    switch ($extension) {
        case 'jpg':
        case 'jpeg':
            $options = array('jpeg_quality' => 97);
            break;
        case 'png':
            $options = array('png_compression_level' => 8);
            break;
        default:
            $options = array();
    }

    return $options;
}


function getPaths($resize_type)
{
// default for all paths,.
    $paths = array(
        'fullsize' => DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'pages',
        'thumbnail' => DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'pages',
    );
// set for product photo uploads
    if ($resize_type === 'thumbnails') {
        $paths['fullsize'] = DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'productphotos';
        $paths['thumbnail'] = DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'productphotos' . DIRECTORY_SEPARATOR . 'small';
    }
// set for stock banner uploads
    if ($resize_type === 'stockbanners') {
        $paths['fullsize'] = DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'stockbanners';
        $paths['thumbnail'] = DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'stockbanners';
    }

    return $paths;
}


function getSrcSet($filename, $resize_type = 'wide')
{
    $root_directory = dirname(__DIR__);

    $paths = getPaths($resize_type);
    // sets the source path for the big images
    $fullsize_directory = $root_directory . $paths['fullsize'];
    // sets the source path for the thumbnail images (prod photos)
    $thumbnail_directory = $root_directory . $paths['thumbnail'];
    
    $images_path = str_replace(DIRECTORY_SEPARATOR, '/', $paths['thumbnail']);
    $srcset = array();

    $widths = getWidths($resize_type);

// Does the original image exist?
if (file_exists($fullsize_directory . DIRECTORY_SEPARATOR . $filename)) {
// If it does, are we dealing with productphotos? We don't want to
// accidentally delete a full-sized image from /pages or /stockbanners
if ($resize_type === 'thumbnails') {
// File with the same name as the original but in the thumbs directory
$old_thumbnail = $thumbnail_directory . DIRECTORY_SEPARATOR . $filename;
// Does this file exist?
if (file_exists($old_thumbnail)) {
// Delete it
unlink($old_thumbnail);
}
}

$basename = pathinfo($filename, PATHINFO_FILENAME);
$extension = pathinfo($filename, PATHINFO_EXTENSION);

foreach ($widths as $size => $width) {
$fullname = $basename . '_' . $size . '.' . $extension;
if (file_exists($thumbnail_directory . DIRECTORY_SEPARATOR . $fullname)) {
$srcset[] = "{$images_path}/{$fullname} {$size}w";
} else {
resizeSingleImage($filename, $size, $width, $resize_type);
$srcset[] = "{$images_path}/{$fullname} {$size}w";
}
}
}

return implode(', ', $srcset);
}


// Returns an array of widths, keyed by target screen size
function getWidths($resize_option)
{
    switch($resize_option) {
        case 'categories':
        case 'products':
        case 'stockbanners':
            $widths = array(
                '475' => 237,
                '768' => 384,
                '1920' => 451,
            );
            break;
        case 'wide':
            $widths = array(
                '475' => 237,
                '768' => 384,
                '1920' => 950,
            );
            break;
        case 'desktopslide':
            $widths = array(
                '475' => 475,
                '768' => 768,
                '1920' => 1920,
            );
            break;
        case 'thumbnails':
            $widths = array(
                '475' => 237,
                '768' => 384,
                '1920' => 451,
                '2520' => 600,
            );
            break;            
        default:
            $widths = array();
            break;
    }

    return $widths;
}


// Takes input from a form post and saves original image plus all required resizes
function resizeImage($path_to_file, $file_name, $resize_type)
{
    $imagine = new Imagine\Gd\Imagine();
    $paths = getPaths($resize_type);
    $fullsize_directory = dirname(__DIR__) . $paths['fullsize'];
    $thumbnail_directory = dirname(__DIR__) . $paths['thumbnail'];
    $pathinfo = pathinfo($file_name);
    $prefix = time();
    $renamed = "{$prefix}_{$pathinfo['basename']}";

    // Open the uploaded image with the Imagine library
    $image = $imagine->open($path_to_file);

    // Save the original
    $options = getImageOptions($pathinfo['extension']);
    $path_to_original = $fullsize_directory . DIRECTORY_SEPARATOR . $renamed;
    $image->save($path_to_original, $options);

    // Resize

    // Get the size of the original image
    $box = $image->getSize();

    // Get the sizes we need
    $widths = getWidths($resize_type);

    // Create resized images
    foreach ($widths as $key => $width) {
        $ratio = $width / $box->getWidth();
        $scaled_box = $box->scale($ratio);
        $new_filename = "{$prefix}_{$pathinfo['filename']}_{$key}.{$pathinfo['extension']}";

        // Re-open the original for scaling so we're not creating a larger image from a smaller
        $source = $imagine->open($path_to_original);
        $source->resize($scaled_box)->save($thumbnail_directory . DIRECTORY_SEPARATOR . $new_filename, $options);
    }
    return $renamed;
}

// Resizes a single image to a specific size and with a specific suffix
function resizeSingleImage($original, $suffix, $width, $save_path)
{
    $imagine = new Imagine\Gd\Imagine();

    $paths = getPaths($save_path);
    // get the source file ready for renaming
    $source_directory = dirname(__DIR__) . $paths['fullsize'];
    // where is the file going to be saved?
    $target_directory = dirname(__DIR__) . $paths['thumbnail'];
    $pathinfo = pathinfo($original);

    // Open the uploaded image with the Imagine library
    $image = $imagine->open($source_directory . DIRECTORY_SEPARATOR . $original);

    // Get the size of the original image
    $box = $image->getSize();

    $ratio = $width / $box->getWidth();
    $scaled_box = $box->scale($ratio);
    $new_filename = "{$pathinfo['filename']}_{$suffix}.{$pathinfo['extension']}";

    $options = getImageOptions($pathinfo['extension']);
    $image->resize($scaled_box)->save($target_directory . DIRECTORY_SEPARATOR . $new_filename, $options);
}
?>
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Image Resizing Script required - a better one...

Post by Celauran »

Let me begin by reiterating that the front end stuff isn't my strong suit, so I'm not 100% certain this approach is correct. You'll want to do some reading on that.

That said, we're talking about adding the original image to the srcset array. You're already passing in the filename, you know which directory it's in, so all you really need to do is get the width of the image and then append that to the array. This could be done before or after the foreach loop. Want to take a crack at it?
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Image Resizing Script required - a better one...

Post by simonmlewis »

The bit that I am having trouble with is the output.
For each of those _475 srcsets, we are echoing $filename_$size.$ext.
But in this scenario, we don't want the _size in there. So now sure how to put that into the function.....
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Image Resizing Script required - a better one...

Post by simonmlewis »

The nagging thing in my mind, is that from what I have read, I shouldn't have to do this.
It should be defaulting to the main src image, because the screen resolution is bigger than 1920.
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Image Resizing Script required - a better one...

Post by Celauran »

simonmlewis wrote:The bit that I am having trouble with is the output.
For each of those _475 srcsets, we are echoing $filename_$size.$ext.
But in this scenario, we don't want the _size in there. So now sure how to put that into the function.....
You've got $filename, which you can pass straight in. All you need to do is get the width of the image so you can do

Code: Select all

"{$images_path}/{$filename} {$width}w";
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Image Resizing Script required - a better one...

Post by Celauran »

simonmlewis wrote:The nagging thing in my mind, is that from what I have read, I shouldn't have to do this.
It should be defaulting to the main src image, because the screen resolution is bigger than 1920.
What little I've read suggests that srcset supersedes src and that the src attribute basically becomes a fallback for browsers that don't understand srcset. I've generally used it in terms of pixel density, not necessarily widths, but we would always use 1x, 1.5x, 2x.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Image Resizing Script required - a better one...

Post by Celauran »

This does appear to be borne out by some quick experimentation. My laptop has a 13 inch retina display, so 1280px wide, 2x pixel density. I'm uploading a 3840x2160 image and generating smaller versions at 320, 640, 1280, and 2560 px. The srcset contains each of those as well as the full size image and my display uses the 2560 as expected. If I remove the 2560 from the srcset, then it correctly uses the full sized image as that's closer to 2560 than the 1280 would be (it's actually the exact same difference, but it prefers the larger, crisper image).
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Image Resizing Script required - a better one...

Post by simonmlewis »

So are you saying I have to tell in the function, what to use for 2560?
Also, I see where that {$filename} code is, but everything I understand about it, is that it will echo in the code _2560 on the end of the filename, and then look for that file.
So I assume in adding it in here:

Code: Select all

        case 'categories':
        case 'products':
        case 'stockbanners':
            $widths = array(
                '475' => 237,
                '768' => 384,
                '1920' => 451,
            );
            break;
I need to start there, and work down. But I'm lost because this is not using the size extension.
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Image Resizing Script required - a better one...

Post by Celauran »

No, adding it there would cause a new image with _2560 to be created. I don't think that's what you want.

Code: Select all

function getSrcSet($filename, $resize_type = 'wide')
{
    $root_directory = getRootDirectory();

    $paths = getPaths($resize_type);
    $fullsize_directory = $root_directory . $paths['fullsize'];
    $thumbnail_directory = $root_directory . $paths['thumbnail'];

    $images_path = str_replace(DIRECTORY_SEPARATOR, '/', $paths['thumbnail']);
    $srcset = [];

    $widths = getWidths($resize_type);

    if (file_exists($fullsize_directory . DIRECTORY_SEPARATOR . $filename)) {
        if ($resize_type === 'thumbnails') {
            deleteFile($thumbnail_directory . DIRECTORY_SEPARATOR . $filename);
        }

        $basename = pathinfo($filename, PATHINFO_FILENAME);
        $extension = pathinfo($filename, PATHINFO_EXTENSION);

        foreach ($widths as $size => $width) {
            $fullname = $basename . '_' . $size . '.' . $extension;
            if (file_exists($thumbnail_directory . DIRECTORY_SEPARATOR . $fullname)) {
                $srcset[] = "{$images_path}/{$fullname} {$width}w";
            } else {
                resizeSingleImage($filename, $size, $width, $resize_type);
                $srcset[] = "{$images_path}/{$fullname} {$width}w";
            }
        }

        // You've added all the resized images in the loop above
        // You have the filename of the original image
        // Could you not get its width and add it to srcset here?
    }

    return implode(', ', $srcset);
}
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Image Resizing Script required - a better one...

Post by simonmlewis »

God I am getting a brain freeze. Yes I can see $filename in there.
The $resize_type is telling it products, or categories or wide. I need this applied to all three.
So I guess this needs to process only if the $resize_type is one of those three, then put which image to use, for 2560....
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Image Resizing Script required - a better one...

Post by Celauran »

simonmlewis wrote:The $resize_type is telling it products, or categories or wide. I need this applied to all three.
So I guess this needs to process only if the $resize_type is one of those three, then put which image to use, for 2560....
So if the type is thumbnails or stockbanners you don't want the full-size image?
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Image Resizing Script required - a better one...

Post by simonmlewis »

Correct. Thumbnails and Stockbanners have ALL the images created with the _{value}.
But not the categories, products, wide.

Code: Select all

foreach ($widths as $size => $width) {
$fullname = $basename . '_' . $size . '.' . $extension;

if ($resize_type == "thumbnails" || $resize_type == "stockbanner")
{
  if (file_exists($thumbnail_directory . DIRECTORY_SEPARATOR . $fullname)) 
  {
    $srcset[] = "{$images_path}/{$fullname} {$size}w";
  } 
  else 
  {
    resizeSingleImage($filename, $size, $width, $resize_type);
    $srcset[] = "{$images_path}/{$fullname} {$size}w";
  }
}
else
  {
    if (file_exists($thumbnail_directory . DIRECTORY_SEPARATOR . $fullname)) 
  {
    $srcset[] = "{$images_path}/{$fullname}";
  } 
  else 
  {
    resizeSingleImage($filename, $size, $width, $resize_type);
    $srcset[] = "{$images_path}/{$fullname}";
  }
  }

}
}

return implode(', ', $srcset);
}
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Image Resizing Script required - a better one...

Post by Celauran »

There's a bunch of duplication in there and you're missing the "{$width}w" bit in places.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Image Resizing Script required - a better one...

Post by Celauran »

Also, you're doing this while looping over the resized images. Why?
Post Reply