Brian Scramlin

How Image Resizing Works

Recommended Posts

Hey Everyone,

I have a question that seems like it would have an obvious answer, but I cannot wrap my mind around it:

If I have 

<img src="<?= $page->featuredImage->size(800,500)->url ?>"/>

in an article template, does my server run a resizing script

  • every time someone requests the page?
  • Or, is it resized only the first time it is requested?
  • Or when the page is saved?

The reason I would like to know is because I have created two image processing functions my client requires, but one of them is a paid subscription service to compress the images. I don't want to call the paid API every time a page is loaded or something.

Thanks for fielding my ignorance :P

Share this post


Link to post
Share on other sites

The thumbnail generation does run when this code is executed and the file corresponding to the thumbnail does not exist at that time.

  • Like 1

Share this post


Link to post
Share on other sites

How is it possible for me to run a PHP Function on an image as it is being uploaded? This would be the ideal situation because then anywhere I need to execute the ->size() functions I don't have to re-call my compression service.

Right now all over my website I have something like  tinify($page->image->size(200,200)->url) instead I would rather just have the tinify() function called on the initial save. 

Further, if it was possible to do this for every image including CKEditor body images we would be in business!

Thank you for your help. 

Share this post


Link to post
Share on other sites

There are various topics around this exact use case on the forums. The short version: there's no obvious solution, but things you can do.

Share this post


Link to post
Share on other sites
1 hour ago, Brian Scramlin said:

How is it possible for me to run a PHP Function on an image as it is being uploaded? This would be the ideal situation because then anywhere I need to execute the ->size() functions I don't have to re-call my compression service.

Right now all over my website I have something like  tinify($page->image->size(200,200)->url) instead I would rather just have the tinify() function called on the initial save. 

Further, if it was possible to do this for every image including CKEditor body images we would be in business!

Thank you for your help. 

Tinifying images is ONLY useful on the final variations. Tinifying an original source image is completly WRONG.

This tinifying is often misunderstood.

You can resize an image on upload to variuos varirations and also tinify them, if you exactly know which variations you will need around in your site.

Here is an example how to hook into upload and process something with the image:

 

  • Like 2

Share this post


Link to post
Share on other sites

Thank you, everyone. I appreciate your input. I understand in most scenarios converting the original file on upload is not the best approach. However, in this situation it seems the best way to save on calling my iMagick function and compression function. 

First off, I have never created a Processwire module and am intimidated by the prospect, but I am considering the suggested InputfieldImageThumbs module route.

Here is the original module:

class InputfieldImageThumbs extends WireData implements Module {

    public function init() {
        $this->addHookAfter('InputfieldFile::fileAdded', $this, 'createThumbs');
    }

    public function createThumbs($event) {
        $inputfield = $event->object;
        $image = $event->arguments("pagefile");
        
        $allowedTypes = array(IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF); // allowed image formats
        $detectedType = exif_imagetype($image->filename); // check if file is an image
        if(!in_array($detectedType, $allowedTypes)) return; // if not, exit

        $widths = explode(",", $this->imageWidths, 10); // convert comma separated list to array, limit to 10 values
        $widths = array_filter($widths, 'ctype_digit'); // keep only numeric entries in the array
        
        foreach($widths as $width) {
            $image->size($width,0); // generate image for each defined width
        }
    }
}

Here is a stab at my attempted module. I am very new at this, so please prepare yourself

class tinifyImages extends WireData implements Module {

    public function init() {
        $this->addHookAfter('InputfieldFile::fileAdded', $this, 'tinify');
    }

    public function tinify($event) {
        $inputfield = $event->object;
        $image = $event->arguments("pagefile");
        
        $allowedTypes = array(IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF); // allowed image formats
        $detectedType = exif_imagetype($image->filename); // check if file is an image
        if(!in_array($detectedType, $allowedTypes)) return; // if not, exit

        /* Include Tinify API Resources and Initialize */
        require_once("inc/tinify-php-master/lib/Tinify/Exception.php");
        require_once("inc/tinify-php-master/lib/Tinify/ResultMeta.php");
        require_once("inc/tinify-php-master/lib/Tinify/Result.php");
        require_once("inc/tinify-php-master/lib/Tinify/Source.php");
        require_once("inc/tinify-php-master/lib/Tinify/Client.php");
        require_once("inc/tinify-php-master/lib/Tinify.php");
        \Tinify\setKey("API_KEY");

        //function used to compress with tinify api 
        function tinify($imagePath) {
            $path_parts = pathinfo($imagePath);
            $dirname = $path_parts['dirname'] . '/';
            $filename = $path_parts['filename'];
            $savename = $dirname . $filename . '-compressed.jpg';
            if (!file_exists($_SERVER['DOCUMENT_ROOT'] . $savename)) {
                $source = \Tinify\fromFile($_SERVER['DOCUMENT_ROOT'] . $imagePath);
                $source->toFile($_SERVER['DOCUMENT_ROOT'] . $savename);
            }
            return $savename;
        }
        
        $image = tinify($image->url);
    }
}
?>

Am I close?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Markus Breitinger
      I want to use Particle.js as background of my page. What modules do i need and where must i put the code?
      The usage of particle.js in plain HTML is in the attached files.
      index.css
      index.html
    • By LMD
      I'm wondering if it is possible to add a label to the description input in image fields (in the admin).
      I'm using the module Image Extra, which has labels for each input, but I'd like to add a label to the default 'description' input too. The image below illustrates this:

       
      If there is no way (no hook?) then, I suppose I could just not use the default description and add a new description input with the Image Extra module.  But I thought I'd ask in case I (or others) ever want to do this without using the module (i.e. just the one input required).
      I'm using PW 3.0.98
      Thanks.
      ---
      FYI: yes, that is a cat and not a quilt -- this is on my local dev server and I don't have the actual photos yet! She is on a quilt, so it counts... technically.
       
    • By rst
      I am having problems uploading svg images in the the latest pw 3.0.98. It shows the preview and has the spinner on top of it, and just gets stuck on that.
      Worked fine in the previous version of PW
    • By Noel Boss
      Hi, I'm stuck since hours and don't know what to do. Here is my Problem:
      I try to generate Previews of PDF using imagick. I have 4 PDF, I generate a preview of the first page of the pdf, save it to a temporary file and want to import it using the api into an image field. It works for the later 3 pdf but not the first. I add it to the image field and save it. Inside the function that saves it, the image is stored in 'data' as well as in 'itemsAdded' but as soon as i leave the function, its nowhere to be found.
      Process:
      1. create previewimage using imagick and create Pageimage > works
      2. add image to filed 'filepreviews', returns Pageimages array with image added > okay
      3. save page > returns true
      4. Outside renderPreview method, image is not anymore in 'filepreviews'
      // mymodule // … // foreach($files as $file){ $preview = wire('page')->filepreviews->get('name*='.$file->basename(false)); // if there is no preview image… if (!$preview instanceof Pageimage) { $this->renderPreview($file) // we create one using $this->renderPreview > should return true on successful save dump(wire('page')->filepreviews); // my Image is nowhere to be found $preview = wire('page')->filepreviews->get('name*='.$file->basename(false)); } // end for each // render a preview of an otherwhise not supported file format // return true if sucessfull save private function renderPreview($file) { $page = wire('page'); // get path to temporary image $tempFile = $path.$file->basename(false).'-preview.jpg'; // … some imagick code // … and save it: $imagick->writeImage($tempFile); $img = new Pageimage($page->filepreviews, $tempFile); $img->description = $file->basename(false); // destroy temp image unlink($tempFile); // this is my Pageimage, all good… dump($img); // save image, my Pageimage can be found in data and itemsAdded – all good dump($page->filepreviews->add($img)); $page->of(false); $success = $page->save(); // sucess = true dump($success); return $success; }
       
      Second question:
      Would there a generally better approach? Like using pageFiles somehow. Goal is to be able to use the image api like scale etc – I don't generally need the images to be stored in an image field.
       
    • By Marc
      I want to use the API to duplicate an image from one field to another (on the same page). The duplicated image should be a new file so both fields should not point to the same physical file. The field that holds the image that I want to duplicate is called 'image_front' and the duplicated image should go to a field called 'image_thumb'. Any image that is already attached to image_thumb should be removed because it should hold only one file. The same goes for image_front, it should have only one image. Here's what I have so far:
      $original = $page->image_front; $file = $original->getFile($original); $new = $original->clone($file); $page->save(); $page->image_thumb = $new; $page->save('image_thumb'); This works in the sense that the image is successfully cloned but it is attached to both fields so both fields end up have their original image plus the cloned image. 'Image_thumb' should only have the cloned image and 'image_front' should only have the original image. What would be the best way to remove those images and am I even approaching this correctly?