Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Thumbnailing with LiipImagineBundle

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $10.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Go back to the homepage. We're rendering these images with a width and height of 100. But the image behind this is way bigger! That's wasteful: we don't want the user to wait to download these gigantic images, just to see the tiny thumbnail.

Hello LiipImagineBundle

Google for LiipImagineBundle and find its GitHub page. They have a bunch of docs right here... but most of the information actually lives over on Symfony.com. Click "Download the Bundle" to get there... and then I'll go back to the homepage - lots of good stuff here.

Start back on the Installation page. Copy the composer require line, find your terminal, paste and... go go go!

composer require "liip/imagine-bundle:^2.1"

While we're waiting, head back over to the docs. Thanks to Flex, we don't need to enable the bundle or register the routes - that's automatic. Go back to the homepage of the docs... and click the "Filter Sets" link.

This bundle is pretty sweet. You start by creating something called a "filter set" and giving it a name - like my_thumb or whatever you want. Next, you tell the bundle which filters, or transformations, to apply when you use the my_thumb filter set. And there are a ton of them: you can change the size with the thumbnail filter, add a background, add border color, replace the image entirely with a cat gif - pretty much anything you can dream of. We'll just use the thumbnail transformation, but seriously - check out the full list.

Configuring the Filter Set

Let's go check on the install. Excellent! It's done. And the message is right on: it says we need to get to work in the new config file: liip_imagine.yaml. Go open that: config/packages/liip_imagine.yaml. Uncomment the root key to activate the bundle, leave the driver alone - it defaults to gd - and uncomment filter_sets.

liip_imagine:
# # valid drivers options include "gd" or "gmagick" or "imagick"
# driver: "gd"
#
# # define your filter sets under this option
filter_sets:
... lines 7 - 42

Let's create our first filter set called squared_thumbnail_small. We'll use this on the homepage to reduce the images down to 100 by 100. To do that, uncomment the filters key and I'll copy the thumbnail example from below, move it up here, and uncomment it.

liip_imagine:
... lines 2 - 5
filter_sets:
... lines 7 - 9
squared_thumbnail_small:
filters:
... lines 12 - 42

Set the size to 200 by 200 so it looks good on Retina displays. The mode: outbound is how the thumbnail is applied - you can also use inbound.

liip_imagine:
... lines 2 - 5
filter_sets:
... lines 7 - 9
squared_thumbnail_small:
filters:
thumbnail:
size: [200, 200]
mode: outbound
allow_upscale: true
... lines 17 - 42

And... I think we're ready to go! Copy the squared_thumbnail_small name and go into homepage.html.twig. To use this, it's so nice: |imagine_filter() and then the name.

... lines 1 - 2
{% block body %}
... lines 4 - 20
{% for article in articles %}
<div class="article-container my-1">
<a href="{{ path('article_show', {slug: article.slug}) }}">
<img class="article-img" src="{{ uploaded_asset(article.imagePath)|imagine_filter('squared_thumbnail_small') }}">
... lines 25 - 37
</a>
</div>
{% endfor %}
... lines 41 - 63
{% endblock %}

The Thumbnailing Process

Let's go try it! Watch the image src closely. Refresh! It includes the https://127.0.0.1 part, but that's not important. The path - /media/cache/resolve/squared_thumbnail_small/... blah, blah blah - looks like a path to a physical file, but it's not! This is actually a Symfony route and it's handled by a Symfony controller!

Check it out: at your terminal, run:

php bin/console debug:router

There it is! The first time we refresh, LiipImagineBundle generates this URL. When our browser tries to download the image, it's handled by a controller from the bundle. That controller opens the original image, applies all the filters - just a thumbnail in our case - and returns the transformed image. That's a slow operation: our browser has to wait for all of that to finish.

But, watch what happens when we refresh. Did you see it? The path changed! It was /media/cache/resolve - but the resolve part is now gone! This time, the image is not handled by a Symfony route. Look at your public/ directory: there is now a media/ directory with cache/squared_thumbnail_small/uploads/article_image/astronaut-...jpeg.

The full process looks like this. The first time we refreshed, LiipImagineBundle noticed that no thumbnail file existed yet. So, it created the URL that pointed to the Symfony route & controller. The page finished rendering, and our browser make a second request to that URL to load the image. That request was handled by the controller from the bundle which thumbnailed the image, saved it to the filesystem, and returned it to the user. That's slow.

But when we reloaded the page the second time, LiipImagineBundle noticed that the filename already existed and generated a URL directly to that real file. The request for that image was super fast.

Oh, also check out the .gitignore file. Thanks to the Flex recipe, we're already ignoring the public/media directory: we do not want to commit this stuff: it'll just regenerate if it's missing.

So, yea - it all kinda works perfectly!

Next, let's add another filter set for the show page and add an image preview to the article form.

Leave a comment!

66
Login or Register to join the conversation
Nicky S. Avatar
Nicky S. Avatar Nicky S. | posted 3 years ago

Just in case anyone runs into the issue I had when thumbnail images are not showing and the folders are not generating automatically. My issue was the "gd" driver was mentioned in the video I actually didn't have this installed. I only found out as a red error appeared in the server output but not on the page. Installing it to PHP resolved my issue and files started appearing.

(LINUX)

sudo apt-get update

sudo apt-get install php7.2-gd

2 Reply

Thanks for sharing it Nicky S.!

Reply
Beis Avatar

Hi! I'm getting a 404 from nginx, when calling the controller.
The problem is that, when calling the url :

/media/cache/resolve/squared_thumbnail_small/uploads/article_image/beaatles-5ebf1642097fb.gif

That is something that can understand, because Nginx is trying to find a static file, that obviously it isn't.

So I'm trying to allow to that prefix (/media/) on Nginx configuration, that it serves as php file and not as static file with no luck.

That is my Nginx .conf:

server {
root /var/www/html/upload-files/public/;
index index.php index.html index.htm app_dev.php;

server_name uploadfiles.test;

location / {
try_files $uri /index.php$is_args$args;

}

## Images
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
access_log off;
add_header ETag "";
}

location @rewrite {
rewrite / /index.php;
}

## Execute PHP scripts
location ~ \.php$ {
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-UA-Compatible 'IE=Edge,chrome=1';
add_header X-Processing-Time $request_time;
try_files $uri =404;
fastcgi_pass fpm:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}


Things that I have tried with no luck.(Obviously once at time)

location /media/ { } # Allow access to static files in /media/

location /media/.*\.(js|css|png|jpg|jpeg|gif|ico)$ {


add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-UA-Compatible 'IE=Edge,chrome=1';
add_header X-Processing-Time $request_time;
try_files $uri =404;
fastcgi_pass fpm:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
} # media liip bundle files

location /media {
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-UA-Compatible 'IE=Edge,chrome=1';
add_header X-Processing-Time $request_time;
try_files $uri =404;
fastcgi_pass fpm:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
} # media liip bundle files

location /media {

} # media liip bundle files

Any idea how to allow that routes without getting a 404 from Nginx?

1 Reply

Hey Beis!

Ok, so you're correct that the URL /media/cache/resolve/squared_thumbnail_small/uploads/article_image/beaatles-5ebf1642097fb.gif is meant to be a URL that is handled by Symfony - not one that Nginx serves. Well, Nginx should proxy it through index.php, like any other URL. My guess is that it's the .gif ending that is confusing Nginx. Try putting the URL directly in your browser and removing the .gif extension. If you get a 404 - but it's from *Symfony* (not Nginx), then we'll know the extension is the problem :). I would compare your Nginx config with the official one from the docs - https://symfony.com/doc/cur... - it's written specifically to make Nginx look first for a physical file and then fallback to index.php if none is found (which is exactly what we want). The /media directory should not need any special handling.

Let me know what you find out!

Cheers!

Reply
Beis Avatar
Beis Avatar Beis | weaverryan | posted 2 years ago | edited

Hi weaverryan !
You are right! I took a look to the official nginx config docs from symfony.com and I changed the location like it says!
I also tested it with .gif and it is working as expected!

Thanks :)

Reply

Hello guys!
I also had error in this episode, i've fixed it now.
Try to open link in the new tab in browser and check if error exists.

Main reasons of bug:
- access rights - try to create "media" directory in "public" dir with 777 rights
- incorrectly configured GD library - Imagine\Gd\Imagine::open method throws an exception

Here is my working config

liip_imagine:
driver: 'gd'
resolvers:
default:
web_path: ~
filter_sets:
cache: ~
squared_thumbnail_small:
filters:
thumbnail: { size: [200, 200], mode: outbound, allow_upscale: true }
loaders:
default:
filesystem:
data_root:
- '%kernel.project_dir%/public'

Dockerfile:

FROM php:7.3.6-fpm

RUN apt-get update && apt-get install -y \
git \
wget \
unzip \
libzip-dev \
libmcrypt-dev \
libpng-dev \
libpq-dev \
zlib1g-dev \
libfreetype6-dev \
libjpeg62-turbo-dev \
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& docker-php-ext-install \
pdo \
pdo_mysql \
bcmath \
zip

RUN apt-get update \
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
&& docker-php-ext-install -j$(nproc) gd

RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

1 Reply

Hey adamsafr

Check the permissions of the folder where you are trying to upload your images. Also, can you show me the error stack trace? I'm not sure about what's going on

Cheers!

Reply

Hi MolloKhan ! I fixed this :)
saw that guys have errors with thumbnails
I attached my liip_imagine config file and dockerfile config in comment above if someone needs it

Reply

Great! Thanks for sharing it to others

Cheers!

Reply
Nizar Avatar

Hi,
We are still waiting for the continuation of the course

1 Reply

Hello!
Is there an option to config the folder/files permissions? They are created with permissions set to 700 which generates a 403 error in my configuration.
I found in an old version the cache_mkdir_mode option but this has been removed since long time. I did not find what has replaced it.

I am on symfony 5.3 with "oneup/flysystem-bundle" v4.4.1 and "liip/imagine-bundle" v2.7.6
Thx!

Reply

Hey be_tnt

The answer may depends on your environment. Have you read this section of the docs? It may be useful https://symfony.com/doc/cur...

Cheers!

Reply

Thx for the link. I will check it ... but I have this issue since I used oneupflysystem and liip imagine librairies. Before that, the folder and files were created with the correct permissions.

Reply

Hey, I was checking the docs of that bundle and there's a config key you can use to specify your folder/file permissions. Give it a check https://github.com/1up-lab/...

Hope it helps!

Reply
Loqman S. Avatar
Loqman S. Avatar Loqman S. | posted 1 year ago

Hi ! :-)

I noticed that I have a loss of image quality when using a liip imagine filter (thumbnail or relative resize). The image is less clear. Is that possible to prevent that ?

Reply

Hey @Loqman,

You can try to adjust image quality option, you can find some docs here https://github.com/liip/Lii...

Cheers!

Reply
Loqman S. Avatar
Loqman S. Avatar Loqman S. | sadikoff | posted 1 year ago | edited

Thanks for your reply sadikoff !

I tried it right after posting that question 😬 but the result wasn't good enough. I will do without that bundle for now but I will try it again for smaller pictures !

Reply

BTW there is one thing, I forgot to mention, for example if you are working on MacOS you will always get little blurry images, because of retina screen. To solve it properly you should create multiple thumbs with different sizes and use

src-set

Cheers!

Reply
Default user avatar
Default user avatar Fabien Hanna | posted 1 year ago

Hi,
I followed all the steps given. However, when I refresh, no media folder is being created in the uploads por any other place.
Could you please advise why that might happen?

Reply
Juan-Etxenike Avatar
Juan-Etxenike Avatar Juan-Etxenike | posted 1 year ago

Hello I am trying to render the thumbnails through javascript.

1. I have managed to inject imagineCacheManager as a dependency and the urls get sent using this function
$this->imagineCacheManager->getBrowserPath('/public/uploads/media/'.$mediaItem['path'],'squared_thumbnail_small');

2. The data gets correctly sent to the javascript file and the urls get shown but previous to conversion with the "resolve" in the url.
http://localhost:8000/media/cache/resolve/squared_thumbnail_small/public/uploads/media/20171216-133904-60b770c84413d.jpg

I get the "Not Found HttpException" error. triggered by vendor\liip\imagine-bundle\Controller\ImagineController.php

(line 149)

I wonder wether I am just asking to much to the bundle.

Reply

Hey Juan E.!

That sounds like a pretty cool setup actually :). And, everything looks good to me. Regardless of how your use that URL (in JavaScript, in a normal img tag), if you go to that URL, LiipImagineBundle should generate the image. Line 149 is this one:

> throw new NotFoundHttpException(sprintf('Source image for path "%s" could not be found', $path), $exception);

Source: https://github.com/liip/Lii...

It makes me think that there is nothing wrong with your overall approach... but simply that the source image isn't found! You might have some directories misconfigured... or you might have a type in your argument to getBrowserPath(). Do a little digging and see if you can find any issues.

Cheers!

Reply

The configuration file in the version 2.6 of Liip_inagine bundle (for Symfony 5.2) has only the following entries
liip_imagine:
driver: "gd"

The lines have to be added to create the thumbnails (notice the way the thumbnail entry is specified in a single line along with the braces)
filter_sets:
cache: ~
squared_thumbnail_small:
filters:
thumbnail: { size: [253, 253], mode: outbound, allow_upscale: true }

EDIT : I noticed that the indentation has been lost after I saved this comment. Indent the entries appropriately

Reply

Hey sridharpandu

Thanks for sharing it with others. I believe that's due to a change to the recipe of the bundle

Cheers!

1 Reply
Dmitriy Avatar
Dmitriy Avatar Dmitriy | posted 1 year ago

Hi. My images are rendered inside a template of script Vue.js. I cannot use twig filters LiipImagineBundle there.

How can I get thumb of my images in this case?

Reply

Hey Dmitriy!

Excellent question! It depends on how you need to get the data in Vue.

One way would be to render the image url as a data- attribute on the element that you're rendering your Vue component into. Then you could read this when you're rendering your Vue app and pass the image path as a prop. So, your element would look something like:


<div data-image-path="{{ uploaded_asset(article.imagePath)|imagine_filter('squared_thumbnail_small') }}">

The other way, which is probably more common, is when you make an AJAX request to an endpoint (e.g. for a product) and need the thumbnail path for that image. In that case, you'll need to use the ImagineBundle services directly in PHP to add a new field to your AJAX response - e.g. thumbnailUrl. How you do that depends on how you've built your API. They talk a bit about that here - https://github.com/liip/Lii... - that service is autowireable using the CacheManager type-hint (and there are a few other services you can autowire if they are handy https://github.com/liip/Lii... )

Let me know if that helps!

Cheers!

Reply
Simon L. Avatar
Simon L. Avatar Simon L. | posted 2 years ago

Hi there !

Is there a way to use LiipImagineBundle for images stored in private directory (/var for example) ?

As far as I can undertstand, when a file is not public, we have to stream it in the controller in order to make it render / download.

So I checked if I could use LiipImagineBundle inside the controller, but I couldn't figure out how to achieve this... Or maybe is there a better wey to build thumbnails for private images ?

Thanks for your help !

Reply

Hey Stileex,

Good question! I think it's not possible with LiipImagineBundle... Why? Because anyway all the images you'e showing to your users become public, i.e. use may easily download (save) them, so even if they are originally in a private place - they will be public anyway when you will show them to the users - that's how the web works.

Though, I think it should be possible to generate thumbnails from private folders, see the docs about how to generate images in PHP: https://github.com/liip/Lii... - this should helps. I haven't tried it unfortunately, but even if it's not possible by design of the bundle - you still could place the images in public/, but to make them more secure - you may think of some random hashes in their names, this way they will be not guessable for users and they won't be able to download files just guessing the URL. And then you will be able to generate the thumbnail by sending an HTTP request with e.g. Symfony or Guzzle Client to specific URL. The only problem probably would be to use a different names for those thumbnails, otherwise it's still possible to change the URL and get the original image knowing its name.

I hope this helps!

Cheers!

1 Reply
Simon L. Avatar

Hi Victor,

Thanks for your very clear answer :)

I think the "hash name" solution is the simplest way to achieve what I want now (Admin images only visible to Admin).

But there is still a not so bad feature to solve about Article references (as you named them later in this course). All references are private, and then users can download them, and that's working perfectly.

But let's say I want the images among these references to be previewed as thumbnails in the web page, so I guess I should go deeper in the use of the Liip Imagine Bundle according to the link you gave me.

Thanks again for your help :)

Reply

Hey Stileex,

You're welcome, I hope this will help with the clear solution for you! Though, feel free to open an issue and discuss your use case in the repo, it might be a good new feature request I think. Or maybe there's already an existent thread there about handing images from private folder, you probably want to double-check it first

Cheers!

Reply
Metin Ö. Avatar
Metin Ö. Avatar Metin Ö. | posted 2 years ago

Hello friends! I am trying to use the Liip-Bundle following this tut. And it is not going well. I'm on Windows (yo!) and when I start the normal PHP-Built-In server I only get 404s for the /media/cache/resolver images. Only the symfony:server instance renders the images to me. The problem is here that I can't work properly with symfony server because every request has a 2 second delay (TTFB).

Is it possible that the routes are not resolved correctly with the built.in PHP server?

Reply

Hi Metin Ö.!

Sorry you're having trouble! Let's see if we can figure some things out :).

Try this: find a /media/cache/resolver URL (that is currently 404'ing), open it in a new tab, and prefix it with index.php. So you will have something like http://localhost:8000/index.php/media/cache/resolver

Does it work now? My guess is that it will ;). If so, the problem is that the built-in PHP web server is incorrectly *not* executing the request through Symfony - it's sort of looking for a "physical" file at that address and then is 404'ing when it's not there. The official way to solve this is to create a "router" script to help your built-in web server... but it may not be worth it just for this one thing. You might just be better off putting /index.php at the front of the URL when you need to try this. But, you *can* totally also create a "router" script - you can see an example here - https://www.php.net/manual/... - and this is the router script that *used* to come with Symfony that you can steal from ;) https://github.com/symfony/...

> The problem is here that I can't work properly with symfony server because every request has a 2 second delay (TTFB).

Wow! That's super weird! Have you tried it with the --allow-http option? That's a *total* guess that maybe SSL is slowing things down... I'm probably wrong with my wild guess. You can also report an issue here if you'd like :) https://github.com/symfony/cli

Cheers!

Reply
Metin Ö. Avatar

Hi Ryan! Thanks for the help - nice things happend ;) I tried sooo many things, but the idea with index.php/media/ didn't occur to me. So, yes it works... and I will give the router a try, if i cant fix the symfony server issues locally. I did try all the options, even --no-tls,... still above 2 secs. Disabling xdebug, blackfire or shutting down docker-compose didnt help. I have no clue. 🤷‍♂️

Reply
Beniamin Avatar
Beniamin Avatar Beniamin | posted 2 years ago

I have this problem when installing liip

composer require liip/imagine-bundle
You are running Composer with SSL/TLS protection disabled.
Using version ^2.3 for liip/imagine-bundle
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Restricting packages listed in "symfony/symfony" to "4.2.*"
Your requirements could not be resolved to an installable set of packages.

Problem 1
- Installation request for liip/imagine-bundle ^2.3 -> satisfiable by liip/imagine-bundle[2.3.0].
- liip/imagine-bundle 2.3.0 requires symfony/asset ^3.4|^4.3|^5.0 -> no matching package found.

Potential causes:
- A typo in the package name
- The package is not available in a stable-enough version according to your minimum-stability setting
see <https: getcomposer.org="" doc="" 04-schema.md#minimum-stability=""> for more details.
- It's a private package and you forgot to add a custom repository to find it

Read <https: getcomposer.org="" doc="" articles="" troubleshooting.md=""> for further common problems.

Installation failed, reverting ./composer.json to its original content.

Reply

Hey Beniamin

Try to install bundle with composer require liip/imagine-bundle:^2.2, i think it might help

Cheers!

Reply
Beniamin Avatar

did not work for me. in my symfony 5 the probem its solved. Thanks. In this project force the instalation in the json file and composer update and it worked.

Reply

Yeah, it's because liip/imagine-bundle dropped support of Symfony 4.2 in latest release, so that's why I advised to use version 2.2

Anyways, we are working on fixing it on our tutorial code, so thank you very much for report, stay tuned!

Cheers!

Reply
Krzysztof K. Avatar
Krzysztof K. Avatar Krzysztof K. | posted 3 years ago

How to do thumb generation in controller?

All my uploaded images are private (I am using filesystem) and I cannot user filters in twig.

I have tried few things like below:



/**
* @Route("/{asset}/photo/view/{id}/thumb", name="private_photo_view_thumb")
*/
public function photoViewThumb(UploadedFile $file, FileUploader $uploader, FilterService $imagine)
{

// 2) Runtime configuration
$runtimeConfig = [
'thumbnail' => [
'size' => [200, 200]
],
];

$handler = $uploader->getHandler($file->getPath());

$resourcePath = $imagine->getUrlOfFilteredImageWithRuntimeFilters(
$file->getPath(),
'squared_thumbnail_small',
$runtimeConfig
);

$response = new StreamedResponse(function() use ($file, $uploader, $resourcePath) {
$outputStream = fopen('php://output', 'wb');
$fileStream = $uploader->readStream($resourcePath, false);
stream_copy_to_stream($fileStream, $outputStream);
});

$response->headers->set('Content-Type', $file->getMimeType());

return $response;
}

But this bundle cannot see my private files (stored in var folder)

I am getting exception:


Source image "files/cygnus/cat1-jpg-5d778185db17f.jpeg" not found.

I do not understand why it needs path instead of file handler, and how I can set where these thumbs will be generated, mainly I need private thumbs too.

Reply

Hey Krzysztof K.!

Hmm. Can you post a screenshot of the full stack trace? I'm not sure exactly which spot is causing the error. But... my guess is that the getUrlOfFilteredImageWithRuntimeFilters() method doesn't like what you're passing via $file->getPath()? Is that correct? A few things to get started:

1) In theory, if you've configured ImagineBundle to *read* from Flysystem, then if you pass it a path like files/cygnus/cat1-jpg-5d778185db17f.jpeg it would know how/where to fetch that (e.g. it would get that from S3).

2) If you need to write an endpoint that does all the thumbnailing manually (including saving the thumbnailed file back your storage and streaming the image to the user), ImagineBundle becomes a much less appealing option... because you're doing much of the work that *it's* supposed to do. But I'm not saying that you're do something wrong - not at all - you just have a more complex use-case. What I'm saying is that it may be even simpler to graph a more "utility-based" image manipulation library (i.e. a pure PHP lib that is good at manipulating images... and that's all - like Intervention) then, in your controller, read the source image from Flysystem, send it through Intervention, save it back through Flysystem, then serve it to your user. Your controller will look very *similar*, but instead of trying to ask ImagineBundle to thumbnail the file (which is just awkward... as its main use-case is not for you to do this directly in code, but to use the Twig filters) you would do it yourself.

Let me know if this helps!

Cheers!

Reply
Krzysztof K. Avatar

Hi Ryan, it is pretty bad that I cannot use that bundle, I have tested al different paths, and nothing works, Flysystem do not have method to return full path and ImagineBundle has no option to accept file instead of path.

My current solution:




/**
* @Route("/{asset}/photo/view/{id}/thumb", name="private_photo_view_thumb")
*/
public function photoViewThumb(UploadedFile $file, FileUploader $uploader)
{



if (!$uploader->has('thumbs/'.$file->getPath())) {
$imagine = new \Imagine\Gd\Imagine();
$image = $imagine->open(dirname(dirname(dirname(__DIR__))).'/var/uploads/'.$file->getPath());
$size = new \Imagine\Image\Box(300, 300);
$mode = \Imagine\Image\ImageInterface::THUMBNAIL_OUTBOUND;
$thumbnail = $image->thumbnail($size, $mode);
$resourcePath = dirname(dirname(dirname(__DIR__))).'/var/uploads/thumbs/'.$file->getPath();
$thumbnail->save($resourcePath);
}


$response = new StreamedResponse(function() use ($file, $uploader) {
$outputStream = fopen('php://output', 'wb');
$fileStream = $uploader->readStream('thumbs/'.$file->getPath(), false);
stream_copy_to_stream($fileStream, $outputStream);
});


$response->headers->set('Content-Type', $file->getMimeType());


return $response;
}


Reply

Hey Krzysztof K.!

Yea - that's more-or-less what I would have done. I typically prefer Intervention (http://image.intervention.io/) when I need to do direct image manipulations, but that's a minor detail. It's unfortunate the bundle doesn't have a nice interface for these direct manipulations... I think it just hasn't been its main use-case.

Happy you got it working either way!

Cheers!

Reply
Eric Avatar

uploaded_asset(article.imagePath)|imagine_filter('squared_thumbnail_small') is not working as advertised. At least in my case (Sf 4.3 and Liip 2.1.0).
The code example as shown in the video produces an image path as follows: http://localhost:8888/symfonyproject/public/media/cache/resolve/squared_thumbnail_small/symfonyproject/public/uploads/image.jpeg resulting in a broken image. The correct image path is http://localhost:8888/symfonyproject/public/media/cache/squared_thumbnail_small/image.jpeg

The correct path is produced by article.imagePath|imagine_filter('squared_thumbnail_small'). As I'm a Symfony novice I haven't yet figured out how uploaded_asset() and imagine_filter() interfere, so any hint or help or solution is highly appreciated.

EDIT

I also noticed that in my /media/cache directory there is no /uploads subdirectory as seen in the video.

Reply

Hey Eric,

That's because you have the project in a subdirectory that's called "symfonyproject" in your case. I'd recommend you to use the "symfony serve" command or "bin/console server:run" command at least to start the built in server for this project. This way your project will be in the root directory, not in a subdirectory, and then it should work.

Otherwise, you need to add more configuration for your liip config file to get it working in a subdirectory, i.e. override some options with proper paths manually. But when your project is in the the root directory - those paths are determined correctly automatically by the liip bundle.

I hope this helps!

Cheers!

1 Reply
Eric Avatar

Hey Victor, thanks a lot for your fast reaction.
Using the symfony server did solve the issue. But could you point me somewhere, where I can find a way to configure liip bundle with project in subdirectories? I already tried the section at the Symfony Liip Bundle Configuration Page but without any luck.

Reply

Hey Eric,

Looks like there're only 3 options that configure paths in the bundle: web_root, cache_prefix, and data_root. That's something you need to configure for your project.

I hope this helps!

Cheers!

Reply

Hi! I get 404, but the source is right:
src="https://localhost:8000/media/cache/resolve/thumbnail_homepagebiggerone/uploads/article_image/prova.JPG"

But I can see the bundle didn't created the directory in my public dir

Reply

Hey Giacomo,

Hm, probably you have a different config? I mean the path is different in your config? Are you sure it should be "https://localhost:8000/media/cache/resolve/thumbnail_homepagebiggerone/uploads/article_image/prova.JPG"? Are you applying changes to your project? Or did you download the course code and start from start/ directory? Could you show your LiipImagineBundle config?

Cheers!

Reply

Yes, but becuase I needed a different type of thumbnail and I'm not following the course I'm just taking the things that I need and apply them to my project becuase I have developed with simfony for 2 months. Btw here it is:


liip_imagine:
filter_sets:
thumbnail_homepagebiggerone:
filters:
thumbnail:
size: [455,227]
mode: outbound
allow_upscale: true
squared_thumbnail_small:
filters:
thumbnail:
size: [200,200]
mode: outbound
allow_upscale: true

It should be right following what you said in the tutorial

Reply

Hey Giacomo,

I just tried to apply your filter and it works for me file. How did you apply that filter in templates? Do you use "assets()" Twig function as well? This way works for me fine:


<img src="{{ asset('images/space-ice.png')|imagine_filter('thumbnail_homepagebiggerone') }}">

But for me path to this image is the next:
https://localhost:8000/media/cache/resolve/thumbnail_homepagebiggerone/images/space-ice.png

At first, when the image has not been cached yet, and then, when it was cached, the path is:
https://localhost:8000/media/cache/thumbnail_homepagebiggerone/images/space-ice.png

Most probably the source path to the image is 404, so it causes 404 error after applying this filter as well. Please, show how you apply this filter in your HTML code.

Cheers!

Reply
Krzysztof K. Avatar
Krzysztof K. Avatar Krzysztof K. | posted 3 years ago

Hmm I am getting 404 for these thumbs. There was no folder created anywhere (suppose to?)

Partially RESOLVED FOR DEV: I had to run server through bin/console server start

Anyway On production I wont be able to do that, and seems that problem refers to Apache configuration, these requests do not go through index.php and return 404, not sure what I should change to avoid that

it might refer to these lines in my .htaccess:
# If the requested filename exists, simply serve it.
# We only want to let Apache serve files and not directories.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]

But it is stated that only if file exists, in this case file do not exists and this request should be processed by index.php, I am not sure why this do not work.

Reply

Hey Krzysztof,

Are you talking about .htaccess in public/ directory? I suppose you use Apache web server, did you set up the public/ directory as your document root in Apache config? Do you have any symlinks in the actual path of your document root?

It would be good if you could debug things a bit, what is the generated link to your thumb in the HTML? What is your actual path to the image in the file system? Can you find the thumbs in the file system?

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial is built on Symfony 4 but works great in Symfony 5!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "aws/aws-sdk-php": "^3.87", // 3.87.10
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "knplabs/knp-markdown-bundle": "^1.7", // 1.7.1
        "knplabs/knp-paginator-bundle": "^2.7", // v2.8.0
        "knplabs/knp-time-bundle": "^1.8", // 1.9.0
        "league/flysystem-aws-s3-v3": "^1.0", // 1.0.22
        "league/flysystem-cached-adapter": "^1.0", // 1.0.9
        "liip/imagine-bundle": "^2.1", // 2.1.0
        "nexylan/slack-bundle": "^2.0,<2.2.0", // v2.1.0
        "oneup/flysystem-bundle": "^3.0", // 3.0.3
        "php-http/guzzle6-adapter": "^1.1", // v1.1.1
        "sensio/framework-extra-bundle": "^5.1", // v5.2.4
        "stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
        "symfony/asset": "^4.0", // v4.2.3
        "symfony/console": "^4.0", // v4.2.3
        "symfony/flex": "^1.9", // v1.17.6
        "symfony/form": "^4.0", // v4.2.3
        "symfony/framework-bundle": "^4.0", // v4.2.3
        "symfony/orm-pack": "^1.0", // v1.0.6
        "symfony/security-bundle": "^4.0", // v4.2.3
        "symfony/serializer-pack": "^1.0", // v1.0.2
        "symfony/twig-bundle": "^4.0", // v4.2.3
        "symfony/validator": "^4.0", // v4.2.3
        "symfony/web-server-bundle": "^4.0", // v4.2.3
        "symfony/yaml": "^4.0", // v4.2.3
        "twig/extensions": "^1.5" // v1.5.4
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.0", // 3.1.0
        "easycorp/easy-log-handler": "^1.0.2", // v1.0.7
        "fzaninotto/faker": "^1.7", // v1.8.0
        "symfony/debug-bundle": "^3.3|^4.0", // v4.2.3
        "symfony/dotenv": "^4.0", // v4.2.3
        "symfony/maker-bundle": "^1.0", // v1.11.3
        "symfony/monolog-bundle": "^3.0", // v3.3.1
        "symfony/phpunit-bridge": "^3.3|^4.0", // v4.2.3
        "symfony/profiler-pack": "^1.0", // v1.0.4
        "symfony/var-dumper": "^3.3|^4.0" // v4.2.3
    }
}