Jump to content
happywire

Do not create default image variation on image upload

Recommended Posts

How could I please stop ProcessWire from creating the default 0x260 image variation when I upload an image to a page?

One way would be to hook into the "InputfieldFile::fileAdded" method, no?

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

public function remove0x260Variation($event) {
	// Get the object of the uploaded image
	$inputfield = $event->object;
	
	// Must be the "images" input field, otherwise return
	if($inputfield->name != 'images') return; 

	  // https://processwire.com/talk/topic/14840-create-pagefile-or-pageimage/?tab=comments#comment-133328
	  // but instead of doing arguments[0] we do argumentsByName('pagefile'), right??
      $image = $event->argumentsByName("pagefile");
      
	// And then in pseudo code I would try something like
	if ($image->width = 0 && $image->height = 260) {
		$image->remove;
		// or
		$image->delete;
	}
}

Or how else could I tackle this?

What also comes to mind, the default image variation being created and eventually deleted would always happen in this case.
So second part of question is, how can this creation and deletion process be avoided altogether and just have a flag somewhere that says "no default image variation needed"?

edit:
What I also found is that the width and the actualWidth of the default image variation are not equal, so I wonder what use it has to have a key for width and then another key for actualWidth, just wondering..

Edited by happywire
added more info

Share this post


Link to post
Share on other sites

PW needs some thumbnail to show image previews in the admin, so I don't think there's a setting somewhere to avoid creating the default thumb.

You could use file fields instead, but you would miss on all the image-specific API functions... see also:

 

  • Like 1

Share this post


Link to post
Share on other sites

And even after creation of the default image variation, there is no method or way to delete a single variation if I wanted to?

I found http://cheatsheet.processwire.com/files/image-methods/image-removevariations/

but would need that to be able to do stuff like
 

$image->removeVariations($imageVariation0x260)

Curious if that also gets rid of the default variation.

Share this post


Link to post
Share on other sites
20 minutes ago, happywire said:

Curious if that also gets rid of the default variation. 

Even if you delete that variation, as long as you are using the image field, this thumbnail image will be recreated each time you open the page in admin.

What's the exact issue with having this thumbnail? If you do not want to see it within a frontend image gallery, just skip it.

Share this post


Link to post
Share on other sites

Each image has variations.
From those I create a srcset array.
Having an item in there that is not needed/wanted is the issue.
But you are right.
I should not try to make ProcessWire behave in a certain way that would break/go against default functionality.
Instead I will just skip adding that item to the array I am after.
If, like you say, that default variation is always being created there is no use going against that.

Share this post


Link to post
Share on other sites
42 minutes ago, dragan said:

You could instead try to define the default to match one of your image variations you are actually going to use in your srcset with $config->adminThumbOptions:

https://github.com/processwire/processwire/blob/master/wire/config.php#L633

Thank you heaps! Excellent idea!
Also thank you for having mercy with a ProcessWire newcomer. 😉

If I add

$config->adminThumbOptions = array(
    'width' => 180, // max width of admin thumbnail or 0 for proportional to height (@deprecated, for legacy use)
    'height' => 0, // max height of admin thumbnail or 0 for proportional to width
);

to config.php and upload a new image to the page I get a variation of
a) filename then a DOT and then 260x0 then a DOT and the file format. e.g. image-waterfall.260x0.jpg
b) the variation of the image itself being 260px wide and a proportional height value.

So regardless of what I put into $config->adminThumbOptions the 0x260 default variation is being created.

I am now wondering if that has to do with the

'gridSize' => 130, // Squared grid size for images (replaces the 'width' and 'height' settings) 

setting?

If so, what is the squared grid size for images?
Do I need to calculate the square root of the value I want, that cannot be, as then how would I specify what value I want for width for example.
Confused but willing to learn this, hehe.

edit:
I changed values for gridSize and that would make default variations of double the height of the value for gridSize with a proportional width.
So if I have gridSize 200 then I would get a variation of 0x400 in the filename and a file of 400 px height with a proportional width.
So this gridSize setting is kind of beyond my understanding.
What does gridSize do?

Edited by happywire
added more info
  • Like 1

Share this post


Link to post
Share on other sites
37 minutes ago, happywire said:

What does gridSize do?

Let's ping @horst

It would be great to be able to set the exact size of the thumbnails. Yeah, if we can use the same image on the frontend then no unnecessary image variaton is created for sure.

Share this post


Link to post
Share on other sites

GridSize was introduced by my work on the image input field. It's the size of the square images in the grid view of the inputfield. Afaik it is duplicated to cater for hidpi monitors by default.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
2 hours ago, LostKobrakai said:

It's the size of the square images in the grid view of the inputfield.

Aha, so each side of the square has the same length, so if I put 'gridSize'=>250 then each side of that preview in the admin panel should be 250px long?

Regardless of gridSize, when I put

<?php namespace ProcessWire;

// config.php

$config->adminThumbOptions = array(
    'width' => 200, 
    'height' => 0, 
);

into config.php the default image variation is not 200x0 both either 0x260 or 260x0.
How can I get the default image variation to have a width of 180 or 200 and a proportional height please?

  • Like 1

Share this post


Link to post
Share on other sites

You can't. The inputfield does generate one non-cropped preview image with the shorter side being double the gridSize setting. I'm not sure if the adminThumbOption is even used anymore after the new images inputfield replaced the old one.

Share this post


Link to post
Share on other sites
On 3/24/2019 at 11:57 PM, LostKobrakai said:

I'm not sure if the adminThumbOption is even used anymore after the new images inputfield replaced the old one.

Is there a way for me to find out?

Share this post


Link to post
Share on other sites
On 3/23/2019 at 7:55 PM, Autofahrn said:

or, as @dragan said, if you do not need the preview in admin, just use the file field.

I could do that, but that would make it a lot less "nicer" to use for clients.
So I would like to keep using the image field while also having it behave in a different way.
I guess this all points in the direction of "write you own module for it"..

Share this post


Link to post
Share on other sites

I still don't really get what your problem really is though. Like what exactly is not working for you in the current system? Normally you just instruct processwire via the api calls which variants you want to have and processwire takes care for you that those are available. 

Share this post


Link to post
Share on other sites
3 hours ago, LostKobrakai said:

I still don't really get what your problem really is though.

Let me try.. perhaps I am not seeing the forest for the trees..
Given is this syntax for responsive images.

<picture>
	<source
		sizes="(min-width: 640px) 60vw, 100vw"
		srcset="image.200x0.webp 200w,
				image.400x0.webp 400w,
				image.800x0.webp 800w,
				image.1200x0.webp 1200w,
				image.1600x0.webp 1600w,
				image.2000x0.webp 2000w"
		type="image/webp">
	<img
		src="image.400x0.jpg" alt="A rubber duck"
		sizes="(min-width: 640px) 60vw, 100vw"
		srcset="image.200x0.jpg 200w,
				image.400x0.jpg 400w,
				image.800x0.jpg 800w,
				image.1200x0.jpg 1200w,
				image.1600x0.jpg 1600w,
				image.2000x0.jpg 2000w">
</picture>

1.
In order to reach this I create an array for the srcset.
If I go through the variations for each image on a page

<?php

$variations = $image->getVariations($options = ['info' => true]);

the default thumbnail is included, not what I need or want.
I create the variations that I want for the particular site and do so with particular ImageMagick commands when it comes to encoding and compression.
If the default thumbnail is included in the srcset array with different ImageMagick commands it not only messes with the array (including an item that is not supposed to be there) but also "dilutes" the quality of the outcome.

2.
Now would the default thumbnail always have the same filename 0x260 or 260x0 I could easily single this out of my srcset array.
Since this is not the case I cannot use the default assets -> files - page ID folder to get all the images for that page and then create a srcset array from it.

So this means, in order to be able to use the image field and have a nice UI for clients..

a) I need to work in a custom folder that only mirrors the original files uploaded regardless of the variations PW might or might not create

b) in such a custom folder I need to create my exact srcset array as well as image variations I want/need without the default thumbnail

c) such variations created in a custom folder need to adhere to the PW nomenclature so that they can be seen in the "Variations" UI of the image field

d) while also making sure these variations are later copied over to the assets -> files - page ID folder in order for them to come up in the "Variations" UI of the image field.
Well this also won't work since as soon as I copy my variations back over to the assets -> files - page ID folder they are mixed with the default thumbnail.

This not only then gets included in the "Variations" UI of the image field but also leaves a sheer amount of duplicate content on the server.
One "custom" folder inside the assets -> files - page ID folder that is used to create a clean srcset array and the default assets -> files - page ID folder that has all variations, including the default thumbnail as well as, like you said, more variations that modules added later on might or might not create. Especially this "might or might not" scenario is something I cannot support.

Let's have a look at this way of creating a srcset array for jpg.

<?php

if ($page->images) {

$variations = $page->images->getAllVariations();
echo '$variations';
dump($variations);
// This however does not return more info on the single variation
// So you need to go one level deeper

foreach ($page->images as $image) {

    // ########################################################
    // Make jpg srcset array ##################################
    // ########################################################

    dump($image);

    $variations = $image->getVariations($options = ['info' => true]);
    dump($variations);

    usort($variations, function ($a, $b) use ($variations) {
        if ($a == $b) {
            return 0;
        }
        // Compare the values of the 'width' key to each other and sort them
        // Sort from largest to smallest > and from smallest to largest with <
        return $a['width'] > $b['width'] ? 1 : -1;
    });
    echo '$variations';
    dump($variations);

    // Remove first element from the $variations array.
    // http://php.net/manual/en/function.array-shift.php
    // That first element holds the default variation/thumbnail created by ProcessWire
    $removedDefaultThumb = array_shift($variations);

    // this will just output the first element/the removed element
    dump($removedDefaultThumb);

    // this will now hold all the custom created variations as needed/wanted without the default 0x260
    dump($variations);

    $srcsetJpg = array();
    foreach ($variations as $variation => $value) {
        array_push($srcsetJpg, $value['url'] . ' ' . $value['width'] . 'w');
    }
    echo '$srcsetJpg';
    dump($srcsetJpg);
}

Quite clear, if the default thumbnail
a) is not the first element of the array, the srcset array is messed up
b) is later replaced by another variation included through a module added later on, the srcset array is messed up
c) does not have the 0x260 or 260x0 nomenclature (one could try and single it out through that), the srcset array is messed up

 

Now, let's move over to the webp srcset array.

1.
webp files cannot be created by PW at the moment, support for those is in the pipeline, however when that might surface is not clear. Sure there is Horst's patch one can use so that the webp file format is accepted by PW.

2.
webp files or variations therefore need to be created in an external process. If this is to be automated for clients in the background one needs to hook the PW site up to something like this https://github.com/rosell-dk/webp-convert-cloud-service in order to first of all obtain webp files and their variations.

3.
Since webp files are not supported by PW they also do not show up in the "Variations" UI of the image field. There is no way know to me at the moment to even include them there to have a nice visual representation of what variations for an image exist in fact. Sidekick, at the moment the "Variations" UI of the image field also does not sort the variations by width or height keys but by filename resulting in a list that is not ordered.

4.
Let's assume somehow the webp files and their variations are created with an external service and this is automated for the client.
This process needs to make sure that
a) only ever the original jpg files uploaded in the assets -> files - page ID folder are converted and then copied (not moved) to the clean custom folder in order to get a clean webp srcset array from there
b) the amount of webp variations exactly match the amount of jpg variations for that original jpg, but not in the assets -> files - page ID folder but inside the custom folder, as again the contents of the default folder might be touched/edited/overwritten by modules added later on that "might or might not" introduce further variations

5.
Since neither the original jpg or its variations are added to the db and unfortunately the original jpg also does not have a key, i.e. "original", inside the result of getVariations($options = ['info' => true]) there is no clear way to obtain that original file and its variations to then be able to create the exact webp variations of those images.

In short, at least to me, it appears that obtaining a clean way to show responsive images that use the above syntax is/will be quite some work if one wants a solid approach to this.

Last not least, creating variations in the frontend times out, hooking into the process in the backend is fine, albeit I am also, at times, facing timeouts there when using large images.
Telling the client to create "optimized for web variations" before uploading images is, at least for me, out of the equation.

So yeah, perhaps all these points are a result of me not understanding how PW handles a proper responsive image workflow that results on the above responsive image syntax.

If that is the case and you or anyone else here has a simple and solid solution, well that would be great!!

I would really love to start coding up some nice websites with PW instead of dealing with how I can get past the stage of creating responsive images.
And no, I don't really want to divert from the syntax for responsive images given above. https://caniuse.com/#feat=webp just being one of the many reasons.

For what it's worth here is how ideally I like to go about making the webp srcset array for each image on a page..

<?php

// ########################################################
// Make webp srcset array #################################
// ########################################################

// http://cheatsheet.processwire.com/page/built-in-fields-reference/page-id/
dump($page->id);
$pageId = $page->id;

// Then make the page specific assets/files/$pageId url out of it.
$pageWebpBaseUrl = $config->urls->files . $pageId;
dump($pageWebpBaseUrl); // => "/site/assets/files/1016"

$pattern = '!.*' . $pageWebpBaseUrl . '!';

$replacement = $pageWebpBaseUrl;

// Make an empty array that will hold our webp srcset.
$srcsetWebp = array();

foreach (glob($pageAssetsFilesPath . '*.webp') as $filename) {

    echo '<pre>';
    echo "$filename size " . filesize($filename) . "\n";

    echo $filename;

    $filenameSize = getimagesize($filename);
    dump($filenameSize);

    // Looking at the dump you can see that the width of the image
    // is always at key/index [0] of the array.
    dump(getimagesize($filename)[0]);

    // Turn the filename into the url for the webp image
    $webpUrl = preg_replace($pattern, $replacement, $filename);
    dump($webpUrl);

    echo '</pre>';

    array_push(
        $srcsetWebp,
        array(
            'url'      => $webpUrl,
            'filename' => $filename,
            'width'    => $filenameSize[0],
            'height'   => $filenameSize[1],
        )
    );
}
dump($srcsetWebp);

usort($srcsetWebp, function ($a, $b) use ($srcsetWebp) {
    if ($a == $b) {
        return 0;
    }
    // Compare the values of the 'width' key to each other and sort them
    // Sort from largest to smallest > and from smallest to largest with <
    return $a['width'] > $b['width'] ? 1 : -1;
});
echo '$srcsetWebp';
dump($srcsetWebp);

 

Edited by happywire
added more info

Share this post


Link to post
Share on other sites
<picture>
	<img
		src="<?= $image->width(400)->url ?>" alt="<?= $image->description ?>"
		sizes="(min-width: 640px) 60vw, 100vw"
		srcset="<?= $image->width(200)->url ?> 200w,
				<?= $image->width(400)->url ?> 400w,
				<?= $image->width(800)->url ?> 800w,
				<?= $image->width(1200)->url ?> 1200w,
				<?= $image->width(1600)->url ?> 1600w,
				<?= $image->width(2000)->url ?> 2000w">
</picture>

What's wrong with doing it like that? You won't need to care about the naming of any files at all. You can also automate that even more to have customizable sizes for the images.

For the webp topic I have to say I'm not up to speed on horsts work, so I'm not sure how to handle that. 

  • Like 3

Share this post


Link to post
Share on other sites
21 minutes ago, LostKobrakai said:

What's wrong with doing it like that?

Thank you. 😀

It times out on the frontend upon uploading the image and visiting the page in question.
Tried it and cannot have that happen with any client.

Also in that particular case no picture tag is needed.
That means up to 3 times as much or even more data is sent as compared to webp.

Given we strip webp from the requirement and do not do image conversion in the frontend, how else would you go about it?

Take an example where the client uploads a batch of 10 images each between 5-12mb in file size.
Take a given list of variations between 120px width and 5120px or more width.
Only keep the sizes you want without having default or other variations mixed with that srcset.
Make sure you are only using sizes that really exist, so don't have a srcset of 2000px width when the largest variation is 1200px in width.

How would you tackle that?

Share this post


Link to post
Share on other sites
3 hours ago, happywire said:

Take an example where the client uploads a batch of 10 images each between 5-12mb in file size.

First of all I'd limit image size here. You can define max width/height or even pixels in the image field. The image field takes care of that for newly added images.

3 hours ago, happywire said:

Take a given list of variations between 120px width and 5120px or more width.

That's sounds like a very broad range of variations. Are they really necessary? 
If you don't build something like an image library 1920px should be more than enough.

3 hours ago, happywire said:

Only keep the sizes you want without having default or other variations mixed with that srcset.

Using the code @LostKobrakai mentioned before you will upload one (1) image and ProcessWire will take care of everything else. Or you could use Croppable Image 3 that takes care of some things or everything and modify the img/srcset code accordingly to match the module syntax.

 

And to cite @LostKobrakai again:

8 hours ago, LostKobrakai said:

I still don't really get what your problem really is though.

🙂 

Share this post


Link to post
Share on other sites

So without the croppable image module variations are generated on demand. If your clients upload quite big images and you want to generate a maybe even larger than needed set of variations this is going to take some time and even more memory on the initial request. But that's a whole different problem than "how can I not create the default variation for an image" with completely different ways to get to a solution.

7 hours ago, happywire said:

Take a given list of variations between 120px width and 5120px or more width.
Only keep the sizes you want without having default or other variations mixed with that srcset.
Make sure you are only using sizes that really exist, so don't have a srcset of 2000px width when the largest variation is 1200px in width.

I still don't get why you insist on filtering down all available variations wherever they might come from. I expect you have a list of sizes for your srcset defined somewhere, so just use those. You can still check the images dimensions to filter out the sizes you defined greater than the image's dimensions. Something like the following.

<?php

function responsive_image($image, $widths = null) {
  $widths = $widths || [200, 400, 800, 1200, 1600, 2000];
  $default = 400;
  
  $smaller_widths = array_filter($widths, function ($width) use ($image) {
    return $width <= $image->width;
  });
  
  $srcset = array_map(function($width) use ($image) { 
    return "{$image->width($width)->url} {$width}w";
  }, $smaller_widths);
  
  $srcset = implode(", ", $srcset);
  
  return <<<HTML
<img src="{$image->width($default)->url}" alt="{$image->description}" sizes="(min-width: 640px) 60vw, 100vw" srcset="{$srcset}">
HTML;
}

 

  • Like 2

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.

×
×
  • Create New...