I have try the following code:
{{'http://www.other-domain.com/img.jpg'|imagine_filter('face')}}
{{'http://www.my-domain.com/my-img.jpg'|imagine_filter('face')}}
LiipImagineBundle does not generate cache, but I tried the following code:
{{'/my-img.jpg'|imagine_filter('face')}}
Now it works.
Any way to process pictures with absolute URL or remote pictures?
Thanks.
You have to register your own data loader. The loader should load a content from remote using file_get_contents for example and create an instance of Image and return it
Hi, Thanks.
I create a RemoteStreamLoader,
class RemoteStreamLoader implements LoaderInterface
{
protected $imagine;
protected $wrapperPrefix;
public function __construct(ImagineInterface $imagine, $wrapperPrefix)
{
$this->imagine = $imagine;
$this->wrapperPrefix = $wrapperPrefix;
}
public function find($path)
{
return $this->imagine->load(file_get_contents($path));
}
}
with config:
<service id="my.remote_loader" class="MyBundle\Service\RemoteStreamLoader">
<tag name="liip_imagine.data.loader" loader="my.remote_loader" />
<argument type="service" id="liip_imagine" />
<argument>%liip_imagine.formats%</argument>
</service>
filter config:
my_remote_test:
data_loader: my.remote_loader
quality: 75
filters:
thumbnail: { size: [460, 460], mode: outbound }
Nothing happened, any thing I forget to add? Any way to debug the Loader?
I believe it has to be working the way you configured it. There is a bug or I miss something
At the moment, I give the way up, I will give a try to debug the problem to find out why when I have time. Thanks.
Hi,
There are some differences in the docs and the actual way to do this.
Here's what you need:
use Liip\ImagineBundle\Imagine\Data\Loader\LoaderInterface;
use Imagine\Image\ImagineInterface;
class RemoteStreamLoader implements LoaderInterface
{
protected $imagine;
protected $wrapperPrefix;
public function __construct(ImagineInterface $imagine, $wrapperPrefix)
{
$this->imagine = $imagine;
$this->wrapperPrefix = $wrapperPrefix;
}
public function find($path)
{
// The http:// becomes http:/ in the url path due to how routing urls are converted
// so we need to replace it by http:// in order to load the remote file
$path = preg_replace('@\:/(\w)@', '://$1', $path);
return $this->imagine->load(file_get_contents($path));
}
}
use Liip\ImagineBundle\Imagine\Cache\Resolver\WebPathResolver;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class RemoteCacheResolver extends WebPathResolver
{
/**
* {@inheritDoc}
*/
public function resolve(Request $request, $path, $filter)
{
$browserPath = $this->decodeBrowserPath($this->getBrowserPath($path, $filter));
$this->basePath = $request->getBaseUrl();
$targetPath = $this->getFilePath($path, $filter);
// We can't use a folder with "http://" in its name so this will transform the output path name
$targetPath = preg_replace('@http\:/{1,2}(?:\w+\.)?(\w+)\.\w+/@', '$1/', $targetPath);
// if the file has already been cached, we're probably not rewriting
// correctly, hence make a 301 to proper location, so browser remembers
if (file_exists($targetPath)) {
// Strip the base URL of this request from the browserpath to not interfere with the base path.
$baseUrl = $request->getBaseUrl();
if ($baseUrl && 0 === strpos($browserPath, $baseUrl)) {
$browserPath = substr($browserPath, strlen($baseUrl));
}
// We can't use a folder with "http://" in its name so this will transform the output path name
$browserPath = preg_replace('@http\:/{1,2}(?:\w+\.)?(\w+)\.\w+/@', '$1/', $browserPath);
return new RedirectResponse($request->getBasePath().$browserPath);
}
return $targetPath;
}
/**
* Stores the content into a static file.
*
* @param Response $response
* @param string $targetPath
* @param string $filter
*
* @return Response
*
* @throws \RuntimeException
*/
public function store(Response $response, $targetPath, $filter)
{
// We can't use a folder with "http://" in its name so this will transform the output path name
$targetPath = preg_replace('@http\:/{1,2}(?:\w+\.)?(\w+)\.\w+/@', '$1/', $targetPath);
$dir = pathinfo($targetPath, PATHINFO_DIRNAME);
$this->makeFolder($dir);
file_put_contents($targetPath, $response->getContent());
$response->setStatusCode(201);
return $response;
}
}
my.remote_loader:
class: %my.remote_loader.class%
arguments: [@liip_imagine, %liip_imagine.formats%]
tags:
-聽{ name: liip_imagine.data.loader, loader: my_remote_loader }
my.remote_resolver:
class: %my.remote_resolver.class%
arguments: [@filesystem]
tags:
-聽{ name: liip_imagine.cache.resolver, resolver: my_remote_resolver }
The 'tags' parameter is important, and differ from what the docs tell.
liip_imagine:
filter_sets:
cache: ~
square_thumb:
cache: my_remote_resolver
data_loader: my_remote_loader
quality: 75
filters:
thumbnail: { size: [150, 150], mode: outbound }
Hope this helps.
@mechanicalgux solution worked like a charm! Should be in the official documentation. Thanks a lot for that!
One consideration: @mechanicalgux solution's regex to replace http:// to http:/ are not working fine. Sometimes I just don't know why using complex regex instead of just using str_replace('http://', 'http:/', $targetPath);. Did it, and it worked. Thanks!
I'm glad it was useful to at least someone!
About the regex, the goal is not to replace http:// by http:/ but to replace any "http://www.domain.com" or "http:/www.domain.com" by "domain" so the folder name is shorter, and you can't have : or / in a directory name.
I haven't used it enough to find not working cases though, I've only used it on one domain.
@mechanicalgux oh, I see. but, removing completely the http:// how will you do the way back in the DatalLoader to get the original absolute href?
Also, the regex wasn't working for me. I had a domain like http://dev.domain.com/app_dev.php/media/cache/avatar_60/http://domain.s3-website-us-west-2.amazonaws.com/uploads/img.jpeg and it was not removing the http://, so the CacheResolver was trying to create an 'http://' folder and I was getting an error. When I use str_replace, the url is now http:/ and it could create an http:/ folder correclty. And it also could resolve the url in the DataLoader replacing http:/ for http://.
Do you know a better solution to this? And why the regex was not working? To not create a http:/ folder sould be without doubts the best solution.
Thanks a lot for your attention.
The path given to DataLoader is the original path with http://, it's not linked to the CacheResolver.
See this method in the class Liip\ImagineBundle\Controller\ImagineController:
public function filterAction(Request $request, $path, $filter)
{
$targetPath = $this->cacheManager->resolve($request, $path, $filter);
if ($targetPath instanceof Response) {
return $targetPath;
}
try {
$image = $this->dataManager->find($filter, $path);
$response = $this->filterManager->get($request, $filter, $image, $path);
} catch (\Imagine\Exception\RuntimeException $e) {
throw new \RuntimeException(sprintf('Unable to create image for path "%s" and filter "%s". Message was "%s"', $path, $filter, $e->getMessage()), 0, $e);
}
if ($targetPath) {
$response = $this->cacheManager->store($response, $targetPath, $filter);
}
return $response;
}
If the CacheResolver is unable to resolve a cached image, the DataLoader will take the original path.
The regex didn't work because there are 3 dots in the host name.
Replace all 3 regex in the CacheResolver with this one:
@http\:/{1,2}(?:\w+\.)?([\w\.\-]+)\.\w+/@
Also I had a problem with images not found on the remote, and changed the DataLoader so it can replace with a placeholder:
class RemoteStreamLoader implements LoaderInterface
{
// ...
public function find($path)
{
$path = preg_replace('@\:/(\w)@', '://$1', $path);
$fileHeaders = @get_headers($path);
$exists = $fileHeaders[0] == 'HTTP/1.1 404 Not Found' ? false : true;
$image = $exists ? Request::getInstance()->getBinaryFile($path) : file_get_contents(__DIR__.'/../../AppBundle/Resources/public/images/placeholder.jpg');
return $this->imagine->load($image);
}
}
The Request class is only a curl wrapper I made to avoid using file_get_contents().
Im trying to use this solution but now its incompatible with current version of LiipImagineBundle.
Which version do you have installed?
@mgalante It worked for me with v0.21.1
@makasim Is there a reason why this is not built-in the bundle ? This would be a great feature. I could contribute it if necessary.
@flug Could you please remember me what problem you are trying to solve?
@makasim he was trying to get this bundle to work with remote images, gave up and wrote this : https://github.com/flug/imagine-bundle I think there should merely be an extension for this bundle containing the services you described earlier, and not a new bundle. I'm trying to get @flug to make this change, but first, I would like to know whether this could be contributing directly in this bundle or not.
sorry, but I am trying to understand the real problem which you all guys want to solve. It is not clear too me. the code posted is not looking good and clear too. So please describe the problem so I can help you with the solution.
We have images stored on a remote server. We want to resize them and store the result locally (in a cache), so that we can display thumbnails quickly.
Try https://github.com/liip/LiipImagineBundle/blob/master/Binary/Loader/StreamLoader.php loader. I believe it must fit your needs.
We'll have a look at that, thanks a lot !
Could someone post a clean solution with StreamLoader?
EDIT: found these two docs which explains it pretty well :)
https://github.com/liip/LiipImagineBundle/blob/master/Resources/doc/cache-resolver/web_path.rst
https://github.com/liip/LiipImagineBundle/blob/master/Resources/doc/data-loader/stream.rst
the solution of : @mechanicalgux doesn't work anymore. How to use CDN url absolute path asset with filter ?
image.absolutepath|imagine_filter('my_filter_medium')
@ibasaw You need define StreamLoader as service:
app.imagine.cdn_data_loader:
class: "%liip_imagine.binary.loader.stream.class%"
arguments:
- '' # if you store full path in the database
tags:
- { name: 'liip_imagine.binary.loader', loader: 'cdn_data_loader' }
And to config:
filter_sets:
my_filter_medium:
data_loader: cdn_data_loader
filters: # your filter
@maxlipsky I can not run the code, do you know of any place where there is a complete functional example?
thanks a lot
i followed @mechanicalgux advice. i didn't have a services.yml file so i create one in app/config but i get the following error :
[:error] [pid 5101] [client 127.0.0.1:58509] PHP Fatal error: Uncaught exception 'Symfony\Component\DependencyInjection\Exception\InvalidArgumentException' with message 'There is no extension able to load the configuration for "my.remote_loader" (in /var/www/testclean/publishv2/app/config/services.yml). Looked for namespace "my.remote_loader", found "framework", "security", "twig", "monolog", "swiftmailer", "assetic", "doctrine", "sensio_framework_extra", "jms_aop", "jms_di_extra", "jms_security_extra", "raul_fraile_ladybug", "doctrine_mongodb", "stof_doctrine_extensions", "jms_translation", "white_october_pagerfanta", "fos_js_routing", "fos_user", "nelmio_api_doc", "escape_wsse_authentication", "fos_rest", "jms_serializer", "pl_user", "pl_data", "pl_file_manager", "liip_imagine", "web_profiler", "sensio_distribution"' in /var/www/testclean/publishv2/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php:290\nStack trace:\n#0 /var/www/testclean/plantn in /var/www/testclean/publishv2/vendor/symfony/symfony/src/Symfony/Component/Config/Loader/FileLoader.php on line 104, referer: http://publish.testclean/app_dev.php/admin/module/collection/58298b988a2c17a10f8b4567/module/582c64b18a2c17c2654762a8/import_data
in my config.yml i add :
imports:
...
- { resource: services.yml }
I was using version LiipImagineBundle 0.21.1 with Symfony 2.6.4 at the time I wrote the posts. I haven't use this bundle on other projects and haven't updated anything since so I don't know what are the changes made that make the code fail in new versions.
@alainib you need to define crops in your config.yml
liip_imagine:
filter_sets:
cache: ~
square_thumb:
cache: my.remote_resolver
data_loader: my.remote_loader
quality: 75
filters:
thumbnail: { size: [64, 64], mode: outbound }
Place your service.yml file in app/config/service.yml
@mechanicalgux thank for the very fast response.
I use symfony 2.3 and liip dev-master
the error :
There is no extension able to load the configuration for "my.remote_loader" (in /var/www/testclean/publishv2/app/config/services.yml).
My config.yml
liip_imagine:
#cache_clearer: false
#cache_mkdir_mode: 0777
# configure resolvers
resolvers :
# setup the default resolver
default :
# use the default web path
web_path : ~
# your filter sets are defined here
filter_sets :
# use the default cache configuration
cache: ~
square_thumb:
cache: my.remote_resolver
data_loader: my.remote_loader
quality: 75
filters:
thumbnail: { size: [64, 64], mode: outbound }
max_width_900:
filters:
relative_resize: { widen: 900 }
thumb_100_100:
filters:
thumbnail: { size: [100, 100], mode: outbound }
thumb_template:
filters:
crop: { start: [0, 0], size: [270, 350] }
thumb_idao:
filters:
thumbnail: { size: [120, 80], mode: outbound }
thumb_180_120:
filters:
thumbnail: { size: [180, 120], mode: outbound }
thumb_370_210:
filters:
thumbnail: { size: [370, 210], mode: outbound }
thumb_130_75:
filters:
thumbnail: { size: [130, 75], mode: outbound }
thumb_max_width_100:
filters:
relative_resize: { widen: 100 }
`
my twig :
<a href="{{ asset(img) }}" class="grouped_elements" rel="group" title="{{ row.copyright }}">
<img src="{{ asset(img) | imagine_filter('square_thumb') }}" alt="{{ imgspe }}" border="0" />
</a>
i put RemoteStreamLoader.php in
.../vendor/liip/imagine-bundle/Liip/ImagineBundle/Binary/Loader/
i put RemoteCacheResolver.php in
.../vendor/liip/imagine-bundle/Liip/ImagineBundle/Imagine/Cache/Resolver/
i did'nt do anything else ( i'm new in symfony coming from JS, the added filed should not be loaded somewhere ?)
What i'm missing ? thanks
@alainib did you assign the correct class to your my.remote_loader service?
In my previous snippet I wrote:
my.remote_loader:
class: %my.remote_loader.class%
But you need to define the parameter my.remote_loader.class, or simply directly point to your class:
my.remote_loader:
class: AppBundle\Service\RemoteStreamLoader
(in service.yml)
Hello upgrade.md has:
[Configuration] liip_imagine.formats option was removed.
[Configuration] liip_imagine.data_root option was removed.
And I have this error:
The service "app.remote_loader" has a dependency on a non-existent parameter "liip_imagine.formats". Did you mean this: "liip_imagine.gd.class"?
Else your code have a problem now, WebPathResolver class has implements ResolverInterface.
I can't pass Request to resolve() function like that, need a scope with a constructor maybe?
Hello,
After trying several ways to get the job done, I succeeded with the following configuration thanks to @maxlipsky.
I hope this can help :)
_composer.json_
"liip/imagine-bundle": "^1.9"
_routing.yml_
# LiipImagineBundle
_liip_imagine:
resource: "@LiipImagineBundle/Resources/config/routing.xml"
_services.yml_
services:
app.imagine.cdn_data_loader:
class: "%liip_imagine.binary.loader.stream.class%"
arguments:
- '' # if you store full path in the database
tags:
- { name: 'liip_imagine.binary.loader', loader: 'cdn_data_loader' }
_config.yml_
data_loader: cdn_data_loader is the important part here
# LiipImagineBundle
liip_imagine:
data_loader: cdn_data_loader
filter_sets:
header_logo:
quality: 100
filters:
thumbnail: { size: [150, 90], mode: outbound }
# ...
<img src="{{ INSERT YOUR URL HERE |imagine_filter('header_logo') }}" />
This service works with the "liip/imagine-bundle": "^2.1" version. ;)
app.imagine.cdn_data_loader:
class: Liip\ImagineBundle\Binary\Loader\StreamLoader
arguments:
- '' # if you store full path in the database
tags:
- { name: 'liip_imagine.binary.loader', loader: 'cdn_data_loader' }
I know this is an old thread, but I couldn't make this work. I have another default loader so I modified the data_loader in the specified filter_set but to no end. Would anyone have a complete example on how to make this work (with cdn_data_loader not being the default loader)?
Thank you all
I did a bit of digging into this and it appears this is linked to FilterTrait containing:
public function filter($path, $filter, array $config = [], $resolver = null)
{
return $this->cache->getBrowserPath(parse_url($path, PHP_URL_PATH), $filter, $config, $resolver);
}
From the get go the URL is stripped of the original domain and the image can not be resolved. It seems to come from b77558c98e389bef3a642f4a03745b47925b90d4 but I can't understand what was the reason behind this change.
I only use this bundle for remote (http://) and local files so I wonder what are the impacts for the other streams but stripping the information from the get go seems rather odd.
hey @lsmith77 can you have a look in here. would it be possible to add a full working example to simple chain load local files and remote files to the official docs? the DX for loading remote files is not that cool.
Sorry, this package is in maintenance mode only atm due to capacity limitations. So we are happy to review, merge and tag releases but right now can't do more than that.
Most helpful comment
@ibasaw You need define StreamLoader as service:
And to config: