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 »

In theory, how I had it in the first place was fine, as I did get it working.
Then I saw it causing errors no the live demo, and started making changes based on the demo throwing those errors.

I'm sort of lost now on where to go with it. Frustrating!
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 »

Your directory structure on local and on the demo server should be the same, right? The absolute paths will be different, of course, but the relative paths for the project itself should be the same. That said, let's focus on getting everything back to working on your local environment, then we can focus on what problems remain on the demo server.
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 »

Agreed on both counts.
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 »

So what is step one to get it back on track....?
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 »

What's the situation on your local right now? What is and isn't working? What errors are being generated? Let's make a list and move through those one by one. Once that's done, demo should also be mostly working. Any few errors that remain on demo that aren't on local can be tackled then.
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 »

Image uploading and resizing WORKS.
Image resizing on the fly, on the banner pages works.
Image resizing on the fly on the category pages does NOT work.
That produces this error:

Code: Select all

Notice: Undefined variable: type in C:\xampp\phpMyAdmin\site-wide\functions\functionConsumerResize.php on line 167

Fatal error: Uncaught exception 'Imagine\Exception\InvalidArgumentException' with message 'File C:\xampp\phpMyAdmin\site-wide\images\pages\4326164538842848bb2.jpg does not exist.' in C:\xampp\phpMyAdmin\site-wide\vendor\imagine\imagine\lib\Imagine\Image\AbstractImagine.php:72 Stack trace: #0 C:\xampp\phpMyAdmin\site-wide\vendor\imagine\imagine\lib\Imagine\Gd\Imagine.php(86): Imagine\Image\AbstractImagine->checkPath('C:\\xampp\\phpMyA...') #1 C:\xampp\phpMyAdmin\site-wide\functions\functionConsumerResize.php(175): Imagine\Gd\Imagine->open('C:\\xampp\\phpMyA...') #2 C:\xampp\phpMyAdmin\site-wide\functions\functionConsumerResize.php(68): resizeSingleImage('432616453884284...', 475, 237, 'thumbnails') #3 C:\xampp\phpMyAdmin\site-wide\includes\categ.inc(570): getSrcSet('432616453884284...', 'thumbnails') #4 C:\xampp\phpMyAdmin\site-wide\index.php(42): include('C:\\xampp\\phpMyA...') #5 C:\xampp\phpMyAdmin\site-wide\index.php(437): getPage(Object(PDO)) #6 {main} thrown in C:\xampp\phpMyAdmin\site-wide\vendor\imagine\imagine\lib\Imagine\Image\AbstractImagine.php on line 72
They all use this:

Code: Select all

        $image = $row->photoprimary;
$srcset = getSrcSet($image, 'thumbnails');
echo "<img src='/images/productphotos/$image' srcset='{$srcset}' alt='$row->title'>";
And the require code is this:

Code: Select all

require_once (dirname(__DIR__) . DIRECTORY_SEPARATOR  . 'functions' . DIRECTORY_SEPARATOR . 'functionConsumerResize.php');
Which I now suspect is incorrect.

But also, because it is looking for this:

[text]'File C:\xampp\phpMyAdmin\site-wide\images\pages\4326164538842848bb2.jpg does not exist[/text]
I rather think something is telling it the wrong info, or the function is gathering it wrongly.
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:Image uploading and resizing WORKS.
Image resizing on the fly, on the banner pages works.
Image resizing on the fly on the category pages does NOT work.
That produces this error:

[text]Notice: Undefined variable: type in C:\xampp\phpMyAdmin\site-wide\functions\functionConsumerResize.php on line 167[/text]
Let's start here. What does your version of functionConsumerResize currently look like? It would appear there is something amiss within that file.
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 »

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);

    if (file_exists($fullsize_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} {$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($type);
    // 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($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);
}

?>
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 »

I see a few things wrong in resizeSingleImage.
  • You have $save_path in the function signature, but you never use it.
  • You reference $type in your getPaths call, but it is not defined.
  • You defined $source_directory but are still trying to grab the original from $target_directory.
Fix those and your problems should go away.
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 »

Mmmm poss an example of me copying and pasting, but I am sure I didn't just do a straight copy.
$type - I don't think that is even correct! Should that not be $resize_type?
$source_directory. Yes I think I can see that. Not sure about $save_path tho.
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 can see the source_directory error.
Not sure about $save_path?? That was in your code.
I see the $type error alot.
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:Mmmm poss an example of me copying and pasting, but I am sure I didn't just do a straight copy.
$type - I don't think that is even correct! Should that not be $resize_type?
$source_directory. Yes I think I can see that. Not sure about $save_path tho.
The important thing to remember here is that variable names are scoped to the function. What this means is that what a variable is called in one function has no bearing whatsoever on what it's called in another.

For a more concrete example, let's look at my resizeSingleImage:

Code: Select all

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

    $paths = getPaths($type);
    $source_directory = dirname(__DIR__) . $paths['fullsize'];
    $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);
}
This gets called from within my getSrcSet function:

Code: Select all

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

    $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)) {
        $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);
}
The key takeaway here is this:

Code: Select all

resizeSingleImage($filename, $size, $width, $resize_type);

Code: Select all

function resizeSingleImage($original, $suffix, $width, $type)
The variable names I pass in don't match how they're referenced inside resizeSingleImage and it doesn't matter. The first argument passed in gets called $original inside the function. the fact that I've passed in a variable called $filename is irrelevant. Same for $size/$suffix, and for $resize_type/$type. $width happens to be the same in both cases, but that's mostly coincidence.
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 »

Ok you have lost me a little.
Are you saying the information from the variable can be passed from one function to another, but with different variable names?
How is that any good for your head if you are trying to "follow" the path of the data?

Do you now see the issue causing these problems then?
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:Are you saying the information from the variable can be passed from one function to another, but with different variable names?
That is precisely what I am saying. A function accepts arguments as spelled out in its signature. It does not -- indeed cannot -- care what they're called outside the scope of the function. The function needs to be concerned only with the data it is given as it cannot possibly know what things are called elsewhere in your application nor should you be forced to name things a specific way just to leverage the functionality provided.
simonmlewis wrote:How is that any good for your head if you are trying to "follow" the path of the data?

Do you now see the issue causing these problems then?
I can see how it's a little confusing at first, but I think I spelled out some of the benefits above. The big thing here is to learn to treat each function as independent. Knowing that the first argument passed to a function will be called $foo inside the function is what matters. What if you didn't pass in a variable at all, but rather a static value?
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 »

Sorry I am still lost.
In PHP my mind thinks that if I store "Fred" in $name, and it is passed thru .... well I suppose I can store it as a different variable if I wanted to.

Just seems a trifle odd. But if that's how it works I am sure there is logic there.

So that is the key to this. Where is it wrong?? I'm guessing $type and $save_path are the key. What have I messed up?
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
Post Reply