Page 17 of 37

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

Posted: Thu Mar 09, 2017 7:21 am
by Celauran
simonmlewis wrote:Yes. So in that function, if it finds the file is NOT there, it starts the resize. But before that it needs to be told what $resize to use.
That can likely be done directly in the <img> tag somewhere?
Might make more sense to have a separate function for that, which can then be called from inside the getSrcSet function. You could then pass the image name and the resize type (products, wide, etc) to the function and get back the correct images.

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

Posted: Thu Mar 09, 2017 7:23 am
by simonmlewis
Sure. So one function for checking it exists. Then within that, calling a second function to resize on the fly.
Sounds good..... how do we start?

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

Posted: Thu Mar 09, 2017 7:26 am
by Celauran
How about something like this?

Code: Select all

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

    return $widths;
}

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

Posted: Thu Mar 09, 2017 7:40 am
by simonmlewis
Ok, so how does the <img> tag tell it which "case" it is? To then identify in that area which one it is using.

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

Posted: Thu Mar 09, 2017 7:43 am
by Celauran
simonmlewis wrote:Ok, so how does the <img> tag tell it which "case" it is? To then identify in that area which one it is using.
The current implementation of getSrcSet accepts an optional second argument which is an array of image suffixes to look for. We can modify that to instead accept a string argument of 'categories', 'wide', etc and use the above function to retrieve both the suffixes (which currently don't change but ostensibly could down the road) and their associated widths. Rather than calling getSrcSet($image), you'd call getSrcSet($image, 'products'). You follow?

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

Posted: Thu Mar 09, 2017 7:45 am
by simonmlewis
Yes I do. getSrcSet($image [is about the image in question], 'products' [tells the script which set of sizings we want to use]).
Yes that makes sense to me. So you are passing both over to the getSrcSet function, which uses $image. And somehow, that function has the sizing function in there, using the second of those options.

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

Posted: Thu Mar 09, 2017 8:31 am
by Celauran
Here's what I've come up with. I have tried to mirror your environment as best I can, but don't count on directories being exactly correct. There may be some tweaking required. Here's the directory structure I'm using:

Code: Select all

project/
  public/ # This is where individual scripts live
    images/
      pages/ # This is where the images are being saved
    includes/ # This is where the resize script lives
  vendor/ # This is where Imagine is installed and where the autoloader lives
And here's the resize script as it stands now:

Code: Select all

<?php

require_once dirname(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 = ['jpeg_quality' => 85];
            break;
        case 'png':
            $options = ['png_compression_level' => 8];
            break;
        default:
            $options = [];
    }

    return $options;
}

function getSrcSet($filename, $resize_type = 'wide')
{
    $root_directory = dirname(__DIR__);
    $images_directory = DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'pages';
    $images_path = '/images/pages'; // Still need this for srcset output
    $source_directory = $root_directory . $images_directory;
    $srcset = [];

    $widths = getWidths($resize_type);

    if (file_exists($source_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($source_directory . DIRECTORY_SEPARATOR . $fullname)) {
                $srcset[] = "{$images_path}/{$fullname} {$size}w";
            } else {
                resizeSingleImage($filename, $size, $width);
                $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':
            $widths = [
                '475' => 237,
                '768' => 384,
                '1920' => 451,
            ];
            break;
        case 'wide':
            $widths = [
                '475' => 237,
                '768' => 384,
                '1920' => 950,
            ];
            break;
        case 'desktopslide':
            $widths = [
                '475' => 475,
                '768' => 768,
                '1920' => 1920,
            ];
            break;
        default:
            $widths = [];
            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();

    $target_directory = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'pages';
    $pathinfo = pathinfo($file_name);
    $prefix = time();

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

    // Save the original
    $options = getImageOptions($pathinfo['extension']);
    $path_to_original = $target_directory . DIRECTORY_SEPARATOR . "{$prefix}{$pathinfo['basename']}";
    $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($target_directory . DIRECTORY_SEPARATOR . $new_filename, $options);
    }
}

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

    $target_directory = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'pages';
    $pathinfo = pathinfo($original);

    // Open the uploaded image with the Imagine library
    $image = $imagine->open($target_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);
}
Sample script where you'd upload the images:

Code: Select all

<?php

require_once __DIR__ . '/includes/resize.php';

// Hard-coded default. Pass in whatever you need.
$resize = 'wide';

// If we have an uploaded image without errors
if (!empty($_FILES) && isset($_FILES['image']) && $_FILES['image']['error'] === 0) {
    resizeImage($_FILES['image']['tmp_name'], $_FILES['image']['name'], $resize);
}

?>

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Image Resizing</title>
    </head>
    <body>
        <form method="POST" enctype="multipart/form-data">
            <input type="file" name="image">
            <button>Submit</button>
        </form>
    </body>
</html>
Sample page where you'd display the images:

Code: Select all

<?php

require_once __DIR__ . '/includes/resize.php';

// Hard-coding an image name just for the sake of demonstration
$image = "tulsa.jpg";

?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Show Image</title>
</head>
<body>
    <img src="/images/pages/<?= $image; ?>" srcset="<?= getSrcSet($image); ?>">
</body>
</html>
This is far from perfect, can still be cleaned up some, and may have a couple of gotchas in there. We can deal with all of that later. Most important right now is that you get it working and, even more important, that you understand how it works.

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

Posted: Thu Mar 09, 2017 8:38 am
by simonmlewis
Ok started with the first syntax.
function getImageOptions($extension)
This is where you tell it the quality to use based on the file extension. So if we want it 95%, we just alter 85 to 95. Easy.

function getSrcSet($filename, $resize_type = 'wide')
Is this based on 'wide' being passed through from the <img> tag? Though I guess the code is the same for all.

I see:
$widths = getWidths($resize_type);
In there. Which calls the next function.

function getWidths($resize_option)
This is the one you was showing me before, based on the type of image passed over.

function resizeImage($path_to_file, $file_name, $resize_type)
Is this the actual resize part? And it does it per 475, 768, 1920?

function resizeSingleImage($original, $suffix, $width)
Not sure why I need this one?

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

Posted: Thu Mar 09, 2017 8:46 am
by Celauran
simonmlewis wrote:Ok started with the first syntax.
function getImageOptions($extension)
This is where you tell it the quality to use based on the file extension. So if we want it 95%, we just alter 85 to 95. Easy.
Right.
simonmlewis wrote:function getSrcSet($filename, $resize_type = 'wide')
Is this based on 'wide' being passed through from the <img> tag? Though I guess the code is the same for all.
That's actually just the default parameter. That's what will be used if you don't provide a second argument. You could call getSrcSet($image, 'categories') instead and that would resize for categories.
simonmlewis wrote:I see:
$widths = getWidths($resize_type);
In there. Which calls the next function.
Precisely. This ties in with my previous point. The widths used will be derived from the value you pass to $resize_type above.
simonmlewis wrote:function getWidths($resize_option)
This is the one you was showing me before, based on the type of image passed over.
Right, though type here means 'categories' or 'products' rather than 'jpg' or 'png'. Just so that's clear.
simonmlewis wrote:function resizeImage($path_to_file, $file_name, $resize_type)
Is this the actual resize part? And it does it per 475, 768, 1920?
Look at how it's being used in the upload page. This takes the tmp_name and the name from the upload, saves the original, and creates the three resized images based on what's passed to $resize_type.
simonmlewis wrote:function resizeSingleImage($original, $suffix, $width)
Not sure why I need this one?
Look at how this is being called from getSrcSet. If an image of a particular size does not exist, we pass it the original, the desired suffix, and the desired width, and this will create that single resized image.

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

Posted: Thu Mar 09, 2017 8:54 am
by simonmlewis
Look at how this is being called from getSrcSet. If an image of a particular size does not exist, we pass it the original, the desired suffix, and the desired width, and this will create that single resized image.
Sorry you have lost me here. Sounds like a fallback, but not sure.

Trying to understand rather than just paste it!!!

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

Posted: Thu Mar 09, 2017 8:58 am
by Celauran
simonmlewis wrote:
Look at how this is being called from getSrcSet. If an image of a particular size does not exist, we pass it the original, the desired suffix, and the desired width, and this will create that single resized image.
Sorry you have lost me here. Sounds like a fallback, but not sure.
It's not a fallback per se. You were talking about generating resized images on the fly. Newly uploaded images will be resized at the time of upload by the resizeImage function. You've surely got some images already uploaded that don't have smaller sizes, so getSrcSet would return an empty string. The addition of this call from within getSrcSet means that if the smaller image doesn't exist, we create it on the spot and include it in the srcset all the same.
simonmlewis wrote:Trying to understand rather than just paste it!!!
Good! That way when it needs some tweaking down the road, you'll understand exactly what does what and minor changes should be trivial to implement.

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

Posted: Thu Mar 09, 2017 9:00 am
by simonmlewis
Ohhhh well funny really, as that was the whole point. :) Wow. Ok. I'll put the code in, but within a separate file.
Then see what occurs!
I'll probably add more comments to it so i can loko back and REALLY get it.

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

Posted: Thu Mar 09, 2017 9:04 am
by simonmlewis
I have put the functions in that one separate functions file.
Included it in this page (though will be in index.php at some stage), and I Get this error for each image:
[text]Warning: Invalid argument supplied for foreach() in C:\xampp\phpMyAdmin\site-wide\functions\functionConsumerResize.php on line 16[/text]

Code: Select all

<?php
function getSrcSet($filename, $desired_sizes = [475, 768, 1920])
{
$root_directory = dirname(__DIR__);
$images_directory = DIRECTORY_SEPARATOR."images".DIRECTORY_SEPARATOR."pages";
$images_path = '/images/pages';

$source_directory = $root_directory . $images_directory;
$file_string = $source_directory . DIRECTORY_SEPARATOR . $filename;
$srcset = [];
if (file_exists($source_directory . DIRECTORY_SEPARATOR . $filename)) {

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

foreach ($desired_sizes as $size) {
$fullname = $basename . '_' . $size . '.' . $extension;
if (file_exists($source_directory .DIRECTORY_SEPARATOR. $fullname)) {
$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':
            $widths = [
                '475' => 237,
                '768' => 384,
                '1920' => 451,
            ];
            break;
        case 'wide':
            $widths = [
                '475' => 237,
                '768' => 384,
                '1920' => 950,
            ];
            break;
        case 'desktopslide':
            $widths = [
                '475' => 475,
                '768' => 768,
                '1920' => 1920,
            ];
            break;
        default:
            $widths = [];
            break;
    }

    return $widths;
}

?>

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

Posted: Thu Mar 09, 2017 9:07 am
by Celauran
Hold up a second. Included what where. It looks like you may have the same functions defined in two different places and, at least in the case of getSrcSet, accepting two different sets of arguments. That's going to be problematic.

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

Posted: Thu Mar 09, 2017 9:09 am
by Celauran
Walk me through what's being included where.