Version Description
(released: 13 Nov 2020) * New convertion method: ffmpeg * Fixed problem in Bulk Convert when files had special characters in their filename * Prevented problems if the plugin gets included twice (can anybody enlighten me on how this might happen?)
For more info, see the closed issues on the 0.19.0 milestone on the github repository
Download this release
Release Info
Developer | rosell.dk |
Plugin | WebP Express |
Version | 0.19.0 |
Comparing to | |
See all releases |
Code changes from version 0.18.3 to 0.19.0
- README.md +11 -3
- README.txt +23 -9
- changelog.txt +9 -0
- composer.json +2 -1
- composer.lock +66 -6
- lib/classes/AdminInit.php +6 -12
- lib/classes/AdminUi.php +9 -0
- lib/classes/BulkConvert.php +91 -7
- lib/classes/Config.php +61 -50
- lib/classes/ConvertHelperIndependent.php +1 -1
- lib/classes/ConvertersHelper.php +5 -1
- lib/classes/DismissableGlobalMessages.php +100 -0
- lib/dismissable-global-messages/0.19.0/meet-ffmpeg-a-working-conversion-method.php +16 -0
- lib/dismissable-global-messages/0.19.0/meet-ffmpeg-better-than-ewww.php +17 -0
- lib/dismissable-global-messages/0.19.0/meet-ffmpeg-better-than-gd.php +16 -0
- lib/migrate/migrate13.php +42 -0
- lib/options/enqueue_scripts.php +1 -1
- lib/options/js/{0.16.0 → 0.19.0}/authorized_sites_bak.js +0 -0
- lib/options/js/{0.16.0 → 0.19.0}/bulk-convert.js +0 -0
- lib/options/js/{0.16.0 → 0.19.0}/converters.js +14 -4
- lib/options/js/{0.16.0 → 0.19.0}/das-popup.js +0 -0
- lib/options/js/{0.16.0 → 0.19.0}/escapeHTML.js +0 -0
- lib/options/js/{0.16.0 → 0.19.0}/image-comparison-slider.js +0 -0
- lib/options/js/{0.16.0 → 0.19.0}/page.js +0 -0
- lib/options/js/{0.16.0 → 0.19.0}/purge-cache.js +0 -0
- lib/options/js/{0.16.0 → 0.19.0}/self-test.js +0 -0
- lib/options/js/{0.16.0 → 0.19.0}/sortable.min.js +0 -0
- lib/options/js/{0.16.0 → 0.19.0}/test-convert.js +0 -0
- lib/options/js/{0.16.0 → 0.19.0}/whitelist.js +1 -1
- lib/options/options/conversion-options/converter-options/ffmpeg.php +35 -0
- lib/options/options/conversion-options/converters.inc +1 -0
- lib/options/page-messages.php +1 -0
- lib/options/page-welcome.php +1 -1
- vendor/composer/autoload_classmap.php +3 -0
- vendor/composer/autoload_psr4.php +1 -0
- vendor/composer/autoload_static.php +11 -0
- vendor/composer/installed.json +68 -6
- vendor/onnov/detect-encoding/.travis.yml +38 -0
- vendor/onnov/detect-encoding/LICENSE +21 -0
- vendor/onnov/detect-encoding/README.md +137 -0
- vendor/onnov/detect-encoding/bin/testsRun.sh +8 -0
- vendor/onnov/detect-encoding/composer.json +61 -0
- vendor/onnov/detect-encoding/infection.json.dist +17 -0
- vendor/onnov/detect-encoding/phpbench.json +3 -0
- vendor/onnov/detect-encoding/src/CodePage.php +96 -0
- vendor/onnov/detect-encoding/src/EncodingDetector.php +244 -0
- vendor/rosell-dk/webp-convert/.github/FUNDING.yml +2 -0
- vendor/rosell-dk/webp-convert/BACKERS.md +17 -12
- vendor/rosell-dk/webp-convert/README.md +25 -4
- vendor/rosell-dk/webp-convert/docs/development.md +74 -0
- vendor/rosell-dk/webp-convert/docs/v1.3/converting/convert-options.md +322 -0
- vendor/rosell-dk/webp-convert/docs/v1.3/converting/convert.md +96 -0
- vendor/rosell-dk/webp-convert/docs/v1.3/converting/converters.md +322 -0
- vendor/rosell-dk/webp-convert/docs/v1.3/serving/convert-and-serve.md +167 -0
- vendor/rosell-dk/webp-convert/docs/v1.3/webp-on-demand/tweaks.md +167 -0
- vendor/rosell-dk/webp-convert/docs/v1.3/webp-on-demand/webp-on-demand.md +133 -0
- vendor/rosell-dk/webp-convert/docs/v1.3/webp-on-demand/without-composer.md +45 -0
- vendor/rosell-dk/webp-convert/docs/v2.0/converting/architecture-q50-w600.jpg +0 -0
- vendor/rosell-dk/webp-convert/docs/v2.0/converting/converters/stack.md +248 -0
- vendor/rosell-dk/webp-convert/docs/v2.0/converting/dice.png +0 -0
- vendor/rosell-dk/webp-convert/docs/v2.0/converting/introduction-for-converting.md +218 -0
- vendor/rosell-dk/webp-convert/docs/v2.0/converting/mouse-q100.jpg +0 -0
- vendor/rosell-dk/webp-convert/docs/v2.0/converting/options.md +346 -0
- vendor/rosell-dk/webp-convert/docs/v2.0/migrating-to-2.0.md +73 -0
- vendor/rosell-dk/webp-convert/docs/v2.0/serving/introduction-for-serving.md +157 -0
- vendor/rosell-dk/webp-convert/docs/v2.0/serving/laravel-nginx-serving.md +116 -0
- vendor/rosell-dk/webp-convert/docs/v2.0/webp-on-demand/tweaks.md +181 -0
- vendor/rosell-dk/webp-convert/docs/v2.0/webp-on-demand/webp-on-demand.md +145 -0
- vendor/rosell-dk/webp-convert/docs/v2.0/webp-on-demand/without-composer.md +58 -0
- vendor/rosell-dk/webp-convert/src/Convert/ConverterFactory.php +3 -0
- vendor/rosell-dk/webp-convert/src/Convert/Converters/Binaries/cwebp-103-linux-x86-64 +0 -0
- vendor/rosell-dk/webp-convert/src/Convert/Converters/Binaries/cwebp-103-mac-10_14 +0 -0
- vendor/rosell-dk/webp-convert/src/Convert/Converters/Binaries/cwebp-110-linux-x86-64 +0 -0
- vendor/rosell-dk/webp-convert/src/Convert/Converters/Binaries/cwebp-110-mac-10_15 +0 -0
- vendor/rosell-dk/webp-convert/src/Convert/Converters/Binaries/{cwebp-103-windows-x64.exe → cwebp-110-windows-x64.exe} +0 -0
- vendor/rosell-dk/webp-convert/src/Convert/Converters/Cwebp.php +17 -8
- vendor/rosell-dk/webp-convert/src/Convert/Converters/Ewww.php +4 -0
- vendor/rosell-dk/webp-convert/src/Convert/Converters/FFMpeg.php +166 -0
- vendor/rosell-dk/webp-convert/src/Convert/Converters/GraphicsMagick.php +10 -2
- vendor/rosell-dk/webp-convert/src/Convert/Converters/ImageMagick.php +2 -2
- vendor/rosell-dk/webp-convert/src/Convert/Converters/Imagick.php +13 -1
- vendor/rosell-dk/webp-convert/src/Convert/Converters/Stack.php +7 -3
- vendor/rosell-dk/webp-convert/src/Helpers/SanityCheck.txt +255 -0
- webp-express.php +4 -5
README.md
CHANGED
@@ -10,7 +10,7 @@ But well, it is developed ([here on github](https://github.com/rosell-dk/webp-ex
|
|
10 |
**News: I have added the vendor folder to the repo. To install the plugin here from github, you can simply download the zip and unzip it in your plugin folder**
|
11 |
|
12 |
## Description
|
13 |
-
|
14 |
|
15 |
### The image converter
|
16 |
The plugin uses the [WebP Convert](https://github.com/rosell-dk/webp-convert) library to convert images to webp. *WebP Convert* is able to convert images using multiple methods. There are the "local" conversion methods: `imagick`, `cwebp`, `vips`, `gd`. If none of these works on your host, there are the cloud alternatives: `ewww` (paid) or connecting to a Wordpress site where you got WebP Express installed and you enabled the "web service" functionality.
|
@@ -37,7 +37,7 @@ The plugin implements the "WebP On Demand" solution described [here](https://git
|
|
37 |
- Better user experience (whether performance goes from terrible to bad, or from good to impressive, it is a benefit)
|
38 |
- Better ranking in Google searches (performance is taken into account by Google)
|
39 |
- Less bandwidth consumption - makes a huge difference in the parts of the world where the internet is slow and costly (you know, ~80% of the world population lives under these circumstances).
|
40 |
-
- Currently ~
|
41 |
- It's great for the environment too! Reducing network traffic reduces electricity consumption which reduces CO2 emissions.
|
42 |
|
43 |
### Recent news
|
@@ -673,10 +673,18 @@ The 0.17.0 release contained binaries with dots in their filenames, which caused
|
|
673 |
### When is feature X coming? / Roadmap
|
674 |
No schedule. I move forward as time allows. I currently spend a lot of time answering questions in the support forum. If someone would be nice and help out answering questions here, it would allow me to spend that time developing. Also, donations would allow me to turn down some of the more boring requests from my customers, and speed things up here.
|
675 |
|
676 |
-
Here are my current plans ahead: 0.
|
677 |
|
678 |
If you wish to affect priorities, it is certainly possible. You can try to argue your case in the forum or you can simply let the money do the talking. By donating as little as a cup of coffee on [ko-fi.com/rosell](https://ko-fi.com/rosell), you can leave a wish. I shall take these wishes into account when prioritizing between new features.
|
679 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
680 |
## Changes in 0.18.3
|
681 |
*(released: 5 Nov 2020)*
|
682 |
* Bugfix: WebP Express uses live tests to determine the capabilities of the server in respect to .htaccess files (using the htaccess-capability-tester library). The results are used for warnings and also for optimizing the rules in the .htaccess files. However, HTTP Requests can fail due to other reasons than the feature not working (ie timeout). Such failures should lead to an indeterminate result, but it was interpreted as if the feature was not working.
|
10 |
**News: I have added the vendor folder to the repo. To install the plugin here from github, you can simply download the zip and unzip it in your plugin folder**
|
11 |
|
12 |
## Description
|
13 |
+
More than 4 out of 5 mobile users are using a browser that is able to display webp images. Yet, on most websites, they are served jpeg images, which are typically double the size of webp images for a given quality. What a waste of bandwidth! This plugin was created to help remedy that situation. With little effort, Wordpress admins can have their site serving autogenerated webp images to browsers that supports it, while still serving jpeg and png files to browsers that does not support webp.
|
14 |
|
15 |
### The image converter
|
16 |
The plugin uses the [WebP Convert](https://github.com/rosell-dk/webp-convert) library to convert images to webp. *WebP Convert* is able to convert images using multiple methods. There are the "local" conversion methods: `imagick`, `cwebp`, `vips`, `gd`. If none of these works on your host, there are the cloud alternatives: `ewww` (paid) or connecting to a Wordpress site where you got WebP Express installed and you enabled the "web service" functionality.
|
37 |
- Better user experience (whether performance goes from terrible to bad, or from good to impressive, it is a benefit)
|
38 |
- Better ranking in Google searches (performance is taken into account by Google)
|
39 |
- Less bandwidth consumption - makes a huge difference in the parts of the world where the internet is slow and costly (you know, ~80% of the world population lives under these circumstances).
|
40 |
+
- Currently ~88% of all traffic, and ~86% of mobile browsing traffic are done with browsers supporting webp. With Apple finally on board (Safari 14.0), these numbers are bound to increase. Check current numbers on [caniuse.com](https://caniuse.com/webp)).
|
41 |
- It's great for the environment too! Reducing network traffic reduces electricity consumption which reduces CO2 emissions.
|
42 |
|
43 |
### Recent news
|
673 |
### When is feature X coming? / Roadmap
|
674 |
No schedule. I move forward as time allows. I currently spend a lot of time answering questions in the support forum. If someone would be nice and help out answering questions here, it would allow me to spend that time developing. Also, donations would allow me to turn down some of the more boring requests from my customers, and speed things up here.
|
675 |
|
676 |
+
Here are my current plans ahead: 0.20 will probably be a file manager-like interface for converting / bulk converting / viewing conversion logs / comparing original vs webp visually - kind of a merge of current "test converter" and "bulk conversion" interfaces, and with an addition of a file explorer. 0.21 might allow excluding certain files and folders. 0.22 could be supporting Save-Data header in Varied Image Responses mode (send extra compressed images to clients who wants to use as little bandwidth as possible). 0.21 might be displaying rules for NGINX. 0.23 might be an effort to allow webp for all browsers using [this javascript library](http://libwebpjs.hohenlimburg.org/v0.6.0/). Unfortunately, the javascript library does not (currently) support srcset attributes, which is why I moved this item down the priority list. We need srcset to be supported for the feature to be useful. 0.21 might be WAMP support. The current milestones, their subtasks and their progress can be viewed here: https://github.com/rosell-dk/webp-express/milestones
|
677 |
|
678 |
If you wish to affect priorities, it is certainly possible. You can try to argue your case in the forum or you can simply let the money do the talking. By donating as little as a cup of coffee on [ko-fi.com/rosell](https://ko-fi.com/rosell), you can leave a wish. I shall take these wishes into account when prioritizing between new features.
|
679 |
|
680 |
+
## Changes in 0.19.0
|
681 |
+
*(released: 13 Nov 2020)*
|
682 |
+
* New convertion method: ffmpeg
|
683 |
+
* Fixed problem in Bulk Convert when files had special characters in their filename
|
684 |
+
* Prevented problems if the plugin gets included twice (can anybody enlighten me on how this might happen?)
|
685 |
+
|
686 |
+
For more info, see the closed issues on the [0.19.0 milestone on the github repository](https://github.com/rosell-dk/webp-express/milestone/36?closed=1)
|
687 |
+
|
688 |
## Changes in 0.18.3
|
689 |
*(released: 5 Nov 2020)*
|
690 |
* Bugfix: WebP Express uses live tests to determine the capabilities of the server in respect to .htaccess files (using the htaccess-capability-tester library). The results are used for warnings and also for optimizing the rules in the .htaccess files. However, HTTP Requests can fail due to other reasons than the feature not working (ie timeout). Such failures should lead to an indeterminate result, but it was interpreted as if the feature was not working.
|
README.txt
CHANGED
@@ -3,8 +3,8 @@ Contributors: rosell.dk
|
|
3 |
Donate link: https://ko-fi.com/rosell
|
4 |
Tags: webp, images, performance
|
5 |
Requires at least: 4.0
|
6 |
-
Tested up to: 5.
|
7 |
-
Stable tag: 0.
|
8 |
Requires PHP: 5.6
|
9 |
License: GPLv3
|
10 |
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
@@ -13,7 +13,7 @@ Serve autogenerated WebP images instead of jpeg/png to browsers that supports We
|
|
13 |
|
14 |
== Description ==
|
15 |
|
16 |
-
|
17 |
|
18 |
### The image converter
|
19 |
The plugin uses the [WebP Convert](https://github.com/rosell-dk/webp-convert) library to convert images to webp. *WebP Convert* is able to convert images using multiple methods. There are the "local" conversion methods: `imagick`, `cwebp`, `vips`, `gd`. If none of these works on your host, there are the cloud alternatives: `ewww` (paid) or connecting to a Wordpress site where you got WebP Express installed and you enabled the "web service" functionality.
|
@@ -40,7 +40,7 @@ The plugin implements the "WebP On Demand" solution described [here](https://git
|
|
40 |
- Better user experience (whether performance goes from terrible to bad, or from good to impressive, it is a benefit)
|
41 |
- Better ranking in Google searches (performance is taken into account by Google)
|
42 |
- Less bandwidth consumption - makes a huge difference in the parts of the world where the internet is slow and costly (you know, ~80% of the world population lives under these circumstances).
|
43 |
-
- Currently ~
|
44 |
- It's great for the environment too! Reducing network traffic reduces electricity consumption which reduces CO2 emissions.
|
45 |
|
46 |
== Installation ==
|
@@ -136,15 +136,18 @@ Bread on the table don't come for free, even though this plugin does, and always
|
|
136 |
* [Mathieu Gollain-Dupont](https://www.linkedin.com/in/mathieu-gollain-dupont-9938a4a/)
|
137 |
* Ruben Solvang
|
138 |
|
139 |
-
**Persons who contributed with ko-fi within the last 30 days (updated biweekly) - Thanks
|
140 |
|
141 |
-
*
|
142 |
-
*
|
143 |
-
*
|
|
|
|
|
144 |
|
145 |
**Persons who contributed with extra generously amounts of coffee / lifetime backing (>30$) - thanks!:**
|
146 |
|
147 |
* Justin - BigScoots ($105)
|
|
|
148 |
* Sebastian ($99)
|
149 |
* Tammy Lee ($90)
|
150 |
* Max Kreminsky ($80)
|
@@ -717,7 +720,7 @@ If you are wondering why Alter HTML are missing some images, it can be due to on
|
|
717 |
= When is feature X coming? / Roadmap =
|
718 |
No schedule. I move forward as time allows. I currently spend a lot of time answering questions in the support forum. If someone would be nice and help out answering questions here, it would allow me to spend that time developing. Also, donations would allow me to turn down some of the more boring requests from my customers, and speed things up here.
|
719 |
|
720 |
-
Here are my current plans ahead: 0.
|
721 |
|
722 |
If you wish to affect priorities, it is certainly possible. You can try to argue your case in the forum or you can simply let the money do the talking. By donating as little as a cup of coffee on [ko-fi.com/rosell](https://ko-fi.com/rosell), you can leave a wish. I shall take these wishes into account when prioritizing between new features.
|
723 |
|
@@ -733,6 +736,14 @@ If you want to make sure that my coffee supplies don't run dry, you can even buy
|
|
733 |
|
734 |
== Changelog ==
|
735 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
736 |
= 0.18.3 =
|
737 |
*(released: 5 Nov 2020)*
|
738 |
* Bugfix: WebP Express uses live tests to determine the capabilities of the server in respect to .htaccess files (using the htaccess-capability-tester library). The results are used for warnings and also for optimizing the rules in the .htaccess files. However, HTTP Requests can fail due to other reasons than the feature not working (ie timeout). Such failures should lead to an indeterminate result, but it was interpreted as if the feature was not working.
|
@@ -1195,6 +1206,9 @@ For older releases, check out changelog.txt
|
|
1195 |
|
1196 |
== Upgrade Notice ==
|
1197 |
|
|
|
|
|
|
|
1198 |
= 0.18.3 =
|
1199 |
* Minor fixes (see changelog)
|
1200 |
|
3 |
Donate link: https://ko-fi.com/rosell
|
4 |
Tags: webp, images, performance
|
5 |
Requires at least: 4.0
|
6 |
+
Tested up to: 5.6
|
7 |
+
Stable tag: 0.19.0
|
8 |
Requires PHP: 5.6
|
9 |
License: GPLv3
|
10 |
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
13 |
|
14 |
== Description ==
|
15 |
|
16 |
+
More than 4 out of 5 mobile users are using a browser that is able to display webp images. Yet, on most websites, they are served jpeg images, which are typically double the size of webp images for a given quality. What a waste of bandwidth! This plugin was created to help remedy that situation. With little effort, Wordpress admins can have their site serving autogenerated webp images to browsers that supports it, while still serving jpeg and png files to browsers that does not support webp.
|
17 |
|
18 |
### The image converter
|
19 |
The plugin uses the [WebP Convert](https://github.com/rosell-dk/webp-convert) library to convert images to webp. *WebP Convert* is able to convert images using multiple methods. There are the "local" conversion methods: `imagick`, `cwebp`, `vips`, `gd`. If none of these works on your host, there are the cloud alternatives: `ewww` (paid) or connecting to a Wordpress site where you got WebP Express installed and you enabled the "web service" functionality.
|
40 |
- Better user experience (whether performance goes from terrible to bad, or from good to impressive, it is a benefit)
|
41 |
- Better ranking in Google searches (performance is taken into account by Google)
|
42 |
- Less bandwidth consumption - makes a huge difference in the parts of the world where the internet is slow and costly (you know, ~80% of the world population lives under these circumstances).
|
43 |
+
- Currently ~88% of all traffic, and ~86% of mobile browsing traffic are done with browsers supporting webp. With Apple finally on board (Safari 14.0), these numbers are bound to increase. Check current numbers on [caniuse.com](https://caniuse.com/webp)).
|
44 |
- It's great for the environment too! Reducing network traffic reduces electricity consumption which reduces CO2 emissions.
|
45 |
|
46 |
== Installation ==
|
136 |
* [Mathieu Gollain-Dupont](https://www.linkedin.com/in/mathieu-gollain-dupont-9938a4a/)
|
137 |
* Ruben Solvang
|
138 |
|
139 |
+
**Persons who contributed with ko-fi within the last 30 days (updated biweekly) - Thanks!**
|
140 |
|
141 |
+
* 10 Nov: Bill Vallance
|
142 |
+
* 5 Nov: Steve from Oz
|
143 |
+
* 31 Oct: Mark from Portland, OR
|
144 |
+
* 27 Oct: Pradeep Maheepala from Watford, UK
|
145 |
+
* 13 Oct: Anonymous
|
146 |
|
147 |
**Persons who contributed with extra generously amounts of coffee / lifetime backing (>30$) - thanks!:**
|
148 |
|
149 |
* Justin - BigScoots ($105)
|
150 |
+
* Bill Vallance ($102)
|
151 |
* Sebastian ($99)
|
152 |
* Tammy Lee ($90)
|
153 |
* Max Kreminsky ($80)
|
720 |
= When is feature X coming? / Roadmap =
|
721 |
No schedule. I move forward as time allows. I currently spend a lot of time answering questions in the support forum. If someone would be nice and help out answering questions here, it would allow me to spend that time developing. Also, donations would allow me to turn down some of the more boring requests from my customers, and speed things up here.
|
722 |
|
723 |
+
Here are my current plans ahead: 0.20 will probably be a file manager-like interface for converting / bulk converting / viewing conversion logs / comparing original vs webp visually - kind of a merge of current "test converter" and "bulk conversion" interfaces, and with an addition of a file explorer. 0.21 might allow excluding certain files and folders. 0.22 could be supporting Save-Data header in Varied Image Responses mode (send extra compressed images to clients who wants to use as little bandwidth as possible). 0.21 might be displaying rules for NGINX. 0.23 might be an effort to allow webp for all browsers using [this javascript library](http://libwebpjs.hohenlimburg.org/v0.6.0/). Unfortunately, the javascript library does not (currently) support srcset attributes, which is why I moved this item down the priority list. We need srcset to be supported for the feature to be useful. 0.21 might be WAMP support. The current milestones, their subtasks and their progress can be viewed here: https://github.com/rosell-dk/webp-express/milestones
|
724 |
|
725 |
If you wish to affect priorities, it is certainly possible. You can try to argue your case in the forum or you can simply let the money do the talking. By donating as little as a cup of coffee on [ko-fi.com/rosell](https://ko-fi.com/rosell), you can leave a wish. I shall take these wishes into account when prioritizing between new features.
|
726 |
|
736 |
|
737 |
== Changelog ==
|
738 |
|
739 |
+
= 0.19.0 =
|
740 |
+
*(released: 13 Nov 2020)*
|
741 |
+
* New convertion method: ffmpeg
|
742 |
+
* Fixed problem in Bulk Convert when files had special characters in their filename
|
743 |
+
* Prevented problems if the plugin gets included twice (can anybody enlighten me on how this might happen?)
|
744 |
+
|
745 |
+
For more info, see the closed issues on the [0.19.0 milestone on the github repository](https://github.com/rosell-dk/webp-express/milestone/36?closed=1)
|
746 |
+
|
747 |
= 0.18.3 =
|
748 |
*(released: 5 Nov 2020)*
|
749 |
* Bugfix: WebP Express uses live tests to determine the capabilities of the server in respect to .htaccess files (using the htaccess-capability-tester library). The results are used for warnings and also for optimizing the rules in the .htaccess files. However, HTTP Requests can fail due to other reasons than the feature not working (ie timeout). Such failures should lead to an indeterminate result, but it was interpreted as if the feature was not working.
|
1206 |
|
1207 |
== Upgrade Notice ==
|
1208 |
|
1209 |
+
= 0.19.0 =
|
1210 |
+
* Added new conversion method (ffmpeg)
|
1211 |
+
|
1212 |
= 0.18.3 =
|
1213 |
* Minor fixes (see changelog)
|
1214 |
|
changelog.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
= 0.18.3 =
|
2 |
*(released: 5 Nov 2020)*
|
3 |
* Bugfix: WebP Express uses live tests to determine the capabilities of the server in respect to .htaccess files (using the htaccess-capability-tester library). The results are used for warnings and also for optimizing the rules in the .htaccess files. However, HTTP Requests can fail due to other reasons than the feature not working (ie timeout). Such failures should lead to an indeterminate result, but it was interpreted as if the feature was not working.
|
1 |
+
= 0.19.0 =
|
2 |
+
*(released: 13 Nov 2020)*
|
3 |
+
* New convertion method: ffmpeg
|
4 |
+
* Fixed problem in Bulk Convert when files had special characters in their filename
|
5 |
+
* Prevented problems if the plugin gets included twice (can anybody enlighten me on how this might happen?)
|
6 |
+
|
7 |
+
For more info, see the closed issues on the [0.19.0 milestone on the github repository](https://github.com/rosell-dk/webp-express/milestone/36?closed=1)
|
8 |
+
|
9 |
+
|
10 |
= 0.18.3 =
|
11 |
*(released: 5 Nov 2020)*
|
12 |
* Bugfix: WebP Express uses live tests to determine the capabilities of the server in respect to .htaccess files (using the htaccess-capability-tester library). The results are used for warnings and also for optimizing the rules in the .htaccess files. However, HTTP Requests can fail due to other reasons than the feature not working (ie timeout). Such failures should lead to an indeterminate result, but it was interpreted as if the feature was not working.
|
composer.json
CHANGED
@@ -5,9 +5,10 @@
|
|
5 |
"license": "MIT",
|
6 |
"require": {
|
7 |
"composer/installers": "^1.0.0",
|
8 |
-
"rosell-dk/webp-convert": "^2.
|
9 |
"rosell-dk/webp-convert-cloud-service": "^2.0.0",
|
10 |
"rosell-dk/dom-util-for-webp": "^0.4.0",
|
|
|
11 |
"rosell-dk/htaccess-capability-tester": "^0.9.0"
|
12 |
},
|
13 |
"require-dev": {
|
5 |
"license": "MIT",
|
6 |
"require": {
|
7 |
"composer/installers": "^1.0.0",
|
8 |
+
"rosell-dk/webp-convert": "^2.4.0",
|
9 |
"rosell-dk/webp-convert-cloud-service": "^2.0.0",
|
10 |
"rosell-dk/dom-util-for-webp": "^0.4.0",
|
11 |
+
"onnov/detect-encoding": "^1.0.0",
|
12 |
"rosell-dk/htaccess-capability-tester": "^0.9.0"
|
13 |
},
|
14 |
"require-dev": {
|
composer.lock
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
5 |
"This file is @generated automatically"
|
6 |
],
|
7 |
-
"content-hash": "
|
8 |
"packages": [
|
9 |
{
|
10 |
"name": "composer/installers",
|
@@ -133,6 +133,66 @@
|
|
133 |
],
|
134 |
"time": "2020-04-07T06:57:05+00:00"
|
135 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
{
|
137 |
"name": "rosell-dk/dom-util-for-webp",
|
138 |
"version": "0.4.0",
|
@@ -308,16 +368,16 @@
|
|
308 |
},
|
309 |
{
|
310 |
"name": "rosell-dk/webp-convert",
|
311 |
-
"version": "2.
|
312 |
"source": {
|
313 |
"type": "git",
|
314 |
"url": "https://github.com/rosell-dk/webp-convert.git",
|
315 |
-
"reference": "
|
316 |
},
|
317 |
"dist": {
|
318 |
"type": "zip",
|
319 |
-
"url": "https://api.github.com/repos/rosell-dk/webp-convert/zipball/
|
320 |
-
"reference": "
|
321 |
"shasum": ""
|
322 |
},
|
323 |
"require": {
|
@@ -380,7 +440,7 @@
|
|
380 |
"png",
|
381 |
"png2webp"
|
382 |
],
|
383 |
-
"time": "2020-
|
384 |
},
|
385 |
{
|
386 |
"name": "rosell-dk/webp-convert-cloud-service",
|
4 |
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
5 |
"This file is @generated automatically"
|
6 |
],
|
7 |
+
"content-hash": "8d87b7a5fbf478fb9601a085868d82b5",
|
8 |
"packages": [
|
9 |
{
|
10 |
"name": "composer/installers",
|
133 |
],
|
134 |
"time": "2020-04-07T06:57:05+00:00"
|
135 |
},
|
136 |
+
{
|
137 |
+
"name": "onnov/detect-encoding",
|
138 |
+
"version": "v1.2.0",
|
139 |
+
"source": {
|
140 |
+
"type": "git",
|
141 |
+
"url": "https://github.com/onnov/detect-encoding.git",
|
142 |
+
"reference": "c88cea4f0c83d7f7e0675f2801e0995f328de1ce"
|
143 |
+
},
|
144 |
+
"dist": {
|
145 |
+
"type": "zip",
|
146 |
+
"url": "https://api.github.com/repos/onnov/detect-encoding/zipball/c88cea4f0c83d7f7e0675f2801e0995f328de1ce",
|
147 |
+
"reference": "c88cea4f0c83d7f7e0675f2801e0995f328de1ce",
|
148 |
+
"shasum": ""
|
149 |
+
},
|
150 |
+
"require": {
|
151 |
+
"ext-iconv": "*",
|
152 |
+
"php": ">=7.2"
|
153 |
+
},
|
154 |
+
"require-dev": {
|
155 |
+
"infection/infection": "*",
|
156 |
+
"phpbench/phpbench": "*",
|
157 |
+
"phpcompatibility/php-compatibility": "*",
|
158 |
+
"phpmd/phpmd": "*",
|
159 |
+
"phpstan/phpstan": "*",
|
160 |
+
"phpstan/phpstan-strict-rules": "*",
|
161 |
+
"phpunit/phpunit": "*",
|
162 |
+
"roave/backward-compatibility-check": "*",
|
163 |
+
"squizlabs/php_codesniffer": "*"
|
164 |
+
},
|
165 |
+
"type": "library",
|
166 |
+
"autoload": {
|
167 |
+
"psr-4": {
|
168 |
+
"Onnov\\DetectEncoding\\": "src/"
|
169 |
+
}
|
170 |
+
},
|
171 |
+
"notification-url": "https://packagist.org/downloads/",
|
172 |
+
"license": [
|
173 |
+
"MIT"
|
174 |
+
],
|
175 |
+
"authors": [
|
176 |
+
{
|
177 |
+
"name": "onnov",
|
178 |
+
"email": "oblnn@yandex.ru"
|
179 |
+
}
|
180 |
+
],
|
181 |
+
"description": "Text encoding definition class instead of mb_detect_encoding. Defines: utf-8, windows-1251, koi8-r, iso-8859-5, ibm866, .....",
|
182 |
+
"homepage": "https://github.com/onnov/detect-encoding",
|
183 |
+
"keywords": [
|
184 |
+
"cyrillic",
|
185 |
+
"encoding",
|
186 |
+
"ibm866",
|
187 |
+
"iconv",
|
188 |
+
"iso-8859-5",
|
189 |
+
"koi8-r",
|
190 |
+
"mb_detect_encoding",
|
191 |
+
"utf-8",
|
192 |
+
"windows-1251"
|
193 |
+
],
|
194 |
+
"time": "2019-09-20T16:11:46+00:00"
|
195 |
+
},
|
196 |
{
|
197 |
"name": "rosell-dk/dom-util-for-webp",
|
198 |
"version": "0.4.0",
|
368 |
},
|
369 |
{
|
370 |
"name": "rosell-dk/webp-convert",
|
371 |
+
"version": "2.4.0",
|
372 |
"source": {
|
373 |
"type": "git",
|
374 |
"url": "https://github.com/rosell-dk/webp-convert.git",
|
375 |
+
"reference": "187a578ee55730f7a128a2f07b4351524b10d47b"
|
376 |
},
|
377 |
"dist": {
|
378 |
"type": "zip",
|
379 |
+
"url": "https://api.github.com/repos/rosell-dk/webp-convert/zipball/187a578ee55730f7a128a2f07b4351524b10d47b",
|
380 |
+
"reference": "187a578ee55730f7a128a2f07b4351524b10d47b",
|
381 |
"shasum": ""
|
382 |
},
|
383 |
"require": {
|
440 |
"png",
|
441 |
"png2webp"
|
442 |
],
|
443 |
+
"time": "2020-11-10T11:24:50+00:00"
|
444 |
},
|
445 |
{
|
446 |
"name": "rosell-dk/webp-convert-cloud-service",
|
lib/classes/AdminInit.php
CHANGED
@@ -2,11 +2,6 @@
|
|
2 |
|
3 |
namespace WebPExpress;
|
4 |
|
5 |
-
use \WebPExpress\Config;
|
6 |
-
use \WebPExpress\State;
|
7 |
-
use \WebPExpress\Option;
|
8 |
-
use \WebPExpress\Multisite;
|
9 |
-
|
10 |
/**
|
11 |
*
|
12 |
*/
|
@@ -29,12 +24,8 @@ class AdminInit
|
|
29 |
|
30 |
public static function runMigrationIfNeeded()
|
31 |
{
|
32 |
-
//
|
33 |
-
|
34 |
-
if (!defined('WEBPEXPRESS_MIGRATION_VERSION')) {
|
35 |
-
// When an update requires a migration, the number should be increased
|
36 |
-
define('WEBPEXPRESS_MIGRATION_VERSION', '12');
|
37 |
-
}
|
38 |
|
39 |
if (WEBPEXPRESS_MIGRATION_VERSION != Option::getOption('webp-express-migration-version', 0)) {
|
40 |
// run migration logic
|
@@ -42,7 +33,7 @@ class AdminInit
|
|
42 |
}
|
43 |
|
44 |
// uncomment next line to test-run a migration
|
45 |
-
//include WEBPEXPRESS_PLUGIN_DIR . '/lib/migrate/
|
46 |
}
|
47 |
|
48 |
public static function pageNowIs($pageId)
|
@@ -82,6 +73,7 @@ class AdminInit
|
|
82 |
add_action('wp_ajax_webpexpress_view_log', array('\WebPExpress\ConvertLog', 'processAjaxViewLog'));
|
83 |
add_action('wp_ajax_webpexpress_purge_cache', array('\WebPExpress\CachePurge', 'processAjaxPurgeCache'));
|
84 |
add_action('wp_ajax_webpexpress_dismiss_message', array('\WebPExpress\DismissableMessages', 'processAjaxDismissMessage'));
|
|
|
85 |
add_action('wp_ajax_webpexpress_self_test', array('\WebPExpress\SelfTest', 'processAjax'));
|
86 |
|
87 |
|
@@ -109,6 +101,8 @@ class AdminInit
|
|
109 |
// PS: Unfortunately Message::addMessage doesnt print until next load now, we should look into that.
|
110 |
add_action("admin_init", array('\WebPExpress\AdminInit', 'runMigrationIfNeeded'));
|
111 |
|
|
|
|
|
112 |
if (Multisite::isNetworkActivated()) {
|
113 |
add_action("network_admin_menu", array('\WebPExpress\AdminUi', 'networAdminMenuHook'));
|
114 |
} else {
|
2 |
|
3 |
namespace WebPExpress;
|
4 |
|
|
|
|
|
|
|
|
|
|
|
5 |
/**
|
6 |
*
|
7 |
*/
|
24 |
|
25 |
public static function runMigrationIfNeeded()
|
26 |
{
|
27 |
+
// When an update requires a migration, the number should be increased
|
28 |
+
define('WEBPEXPRESS_MIGRATION_VERSION', '13');
|
|
|
|
|
|
|
|
|
29 |
|
30 |
if (WEBPEXPRESS_MIGRATION_VERSION != Option::getOption('webp-express-migration-version', 0)) {
|
31 |
// run migration logic
|
33 |
}
|
34 |
|
35 |
// uncomment next line to test-run a migration
|
36 |
+
//include WEBPEXPRESS_PLUGIN_DIR . '/lib/migrate/migrate13.php';
|
37 |
}
|
38 |
|
39 |
public static function pageNowIs($pageId)
|
73 |
add_action('wp_ajax_webpexpress_view_log', array('\WebPExpress\ConvertLog', 'processAjaxViewLog'));
|
74 |
add_action('wp_ajax_webpexpress_purge_cache', array('\WebPExpress\CachePurge', 'processAjaxPurgeCache'));
|
75 |
add_action('wp_ajax_webpexpress_dismiss_message', array('\WebPExpress\DismissableMessages', 'processAjaxDismissMessage'));
|
76 |
+
add_action('wp_ajax_webpexpress_dismiss_global_message', array('\WebPExpress\DismissableGlobalMessages', 'processAjaxDismissGlobalMessage'));
|
77 |
add_action('wp_ajax_webpexpress_self_test', array('\WebPExpress\SelfTest', 'processAjax'));
|
78 |
|
79 |
|
101 |
// PS: Unfortunately Message::addMessage doesnt print until next load now, we should look into that.
|
102 |
add_action("admin_init", array('\WebPExpress\AdminInit', 'runMigrationIfNeeded'));
|
103 |
|
104 |
+
add_action("admin_notices", array('\WebPExpress\DismissableGlobalMessages', 'printMessages'));
|
105 |
+
|
106 |
if (Multisite::isNetworkActivated()) {
|
107 |
add_action("network_admin_menu", array('\WebPExpress\AdminUi', 'networAdminMenuHook'));
|
108 |
} else {
|
lib/classes/AdminUi.php
CHANGED
@@ -11,6 +11,15 @@ use \WebPExpress\Multisite;
|
|
11 |
class AdminUi
|
12 |
{
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
// Add settings link on the plugins page
|
15 |
// The hook was registred in AdminInit
|
16 |
public static function pluginActionLinksFilter($links)
|
11 |
class AdminUi
|
12 |
{
|
13 |
|
14 |
+
public static function getSettingsUrl()
|
15 |
+
{
|
16 |
+
if (Multisite::isNetworkActivated()) {
|
17 |
+
return network_admin_url('settings.php?page=webp_express_settings_page');
|
18 |
+
} else {
|
19 |
+
return admin_url('options-general.php?page=webp_express_settings_page');
|
20 |
+
}
|
21 |
+
}
|
22 |
+
|
23 |
// Add settings link on the plugins page
|
24 |
// The hook was registred in AdminInit
|
25 |
public static function pluginActionLinksFilter($links)
|
lib/classes/BulkConvert.php
CHANGED
@@ -2,6 +2,8 @@
|
|
2 |
|
3 |
namespace WebPExpress;
|
4 |
|
|
|
|
|
5 |
class BulkConvert
|
6 |
{
|
7 |
|
@@ -136,12 +138,86 @@ class BulkConvert
|
|
136 |
|
137 |
if ($addThis) {
|
138 |
|
139 |
-
//
|
140 |
-
|
141 |
-
|
142 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
}
|
144 |
-
$results[] =
|
145 |
}
|
146 |
}
|
147 |
}
|
@@ -185,8 +261,16 @@ class BulkConvert
|
|
185 |
$config = Config::loadConfigAndFix();
|
186 |
$arr = self::getList($config);
|
187 |
|
188 |
-
//
|
189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
wp_die();
|
191 |
}
|
192 |
|
2 |
|
3 |
namespace WebPExpress;
|
4 |
|
5 |
+
use \Onnov\DetectEncoding\EncodingDetector;
|
6 |
+
|
7 |
class BulkConvert
|
8 |
{
|
9 |
|
138 |
|
139 |
if ($addThis) {
|
140 |
|
141 |
+
$path = substr($relDir . "/", 2) . $filename; // (we cut the leading "./" off with substr)
|
142 |
+
|
143 |
+
// Check if the string can be encoded to json (if not: change it to a string that can)
|
144 |
+
if (json_encode($path, JSON_UNESCAPED_UNICODE) === false) {
|
145 |
+
/*
|
146 |
+
json_encode failed. This means that the string was not UTF-8.
|
147 |
+
Lets see if we can convert it to UTF-8.
|
148 |
+
This is however tricky business (see #471)
|
149 |
+
*/
|
150 |
+
|
151 |
+
$encodedToUTF8 = false;
|
152 |
+
|
153 |
+
// First try library that claims to do better than mb_detect_encoding
|
154 |
+
if (!$encodedToUTF8) {
|
155 |
+
$detector = new EncodingDetector();
|
156 |
+
|
157 |
+
$dectedEncoding = $detector->getEncoding($path);
|
158 |
+
|
159 |
+
if ($dectedEncoding !== 'utf-8') {
|
160 |
+
if (function_exists('iconv')) {
|
161 |
+
$res = iconv($dectedEncoding, 'utf-8//TRANSLIT', $path);
|
162 |
+
if ($res !== false) {
|
163 |
+
$path = $res;
|
164 |
+
$encodedToUTF8 = true;
|
165 |
+
}
|
166 |
+
}
|
167 |
+
}
|
168 |
+
|
169 |
+
/*
|
170 |
+
try {
|
171 |
+
// hm, we avoid iconvXtoEncoding, as it has a bug - it is in the issue queue (#5)
|
172 |
+
//$path = $detector->iconvXtoEncoding($path);
|
173 |
+
$encodedToUTF8 = true;
|
174 |
+
} catch (\Exception $e) {
|
175 |
+
|
176 |
+
}*/
|
177 |
+
}
|
178 |
+
|
179 |
+
// Try mb_detect_encoding
|
180 |
+
if (!$encodedToUTF8) {
|
181 |
+
if (function_exists('mb_convert_encoding')) {
|
182 |
+
$encoding = mb_detect_encoding($path, mb_detect_order(), true);
|
183 |
+
if ($encoding) {
|
184 |
+
$path = mb_convert_encoding($path, 'UTF-8', $encoding);
|
185 |
+
$encodedToUTF8 = true;
|
186 |
+
}
|
187 |
+
}
|
188 |
+
}
|
189 |
+
|
190 |
+
if (!$encodedToUTF8) {
|
191 |
+
/*
|
192 |
+
We haven't yet succeeded in encoding to UTF-8.
|
193 |
+
What should we do?
|
194 |
+
1. Skip the file? (no, the user will not know about the problem then)
|
195 |
+
2. Add it anyway? (no, if this string causes problems to json_encode, then we will have
|
196 |
+
the same problem when encoding the entire list - result: an empty list)
|
197 |
+
3. Try wp_json_encode? (no, it will fall back on "wp_check_invalid_utf8", which has a number of
|
198 |
+
things we do not want)
|
199 |
+
4. Encode it to UTF-8 assuming that the string is encoded in the most common encoding (Windows-1252) ?
|
200 |
+
(yes, if we are lucky with the guess, it will work. If it is in another encoding, the conversion
|
201 |
+
will not be correct, and the user will then know about the problem. And either way, we will
|
202 |
+
have UTF-8 string, which will not break encoding of the list)
|
203 |
+
*/
|
204 |
+
|
205 |
+
// https://stackoverflow.com/questions/6606713/json-encode-non-utf-8-strings
|
206 |
+
if (function_exists('mb_convert_encoding')) {
|
207 |
+
$path = mb_convert_encoding($path, "UTF-8", "Windows-1252");
|
208 |
+
} elseif (function_exists('iconv')) {
|
209 |
+
$path = iconv("CP1252", "UTF-8", $path);
|
210 |
+
} elseif (function_exists('utf8_encode')) {
|
211 |
+
// utf8_encode converts from ISO-8859-1 to UTF-8
|
212 |
+
$path = utf8_encode($path);
|
213 |
+
} else {
|
214 |
+
$path = '[cannot encode this filename to UTF-8]';
|
215 |
+
}
|
216 |
+
|
217 |
+
}
|
218 |
+
|
219 |
}
|
220 |
+
$results[] = $path;
|
221 |
}
|
222 |
}
|
223 |
}
|
261 |
$config = Config::loadConfigAndFix();
|
262 |
$arr = self::getList($config);
|
263 |
|
264 |
+
// We use "wp_json_encode" rather than "json_encode" because it handles problems if there is non UTF-8 characters
|
265 |
+
// There should be none, as we have taken our measures, but no harm in taking extra precautions
|
266 |
+
$json = wp_json_encode($arr, JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
267 |
+
if ($json === false) {
|
268 |
+
// TODO: We can do better error handling than this!
|
269 |
+
echo '';
|
270 |
+
} else {
|
271 |
+
echo $json;
|
272 |
+
}
|
273 |
+
|
274 |
wp_die();
|
275 |
}
|
276 |
|
lib/classes/Config.php
CHANGED
@@ -278,6 +278,66 @@ class Config
|
|
278 |
return self::fix(Config::loadConfig(), $checkQualityDetection);
|
279 |
}
|
280 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
281 |
|
282 |
public static $configForOptionsPage = null; // cache the result (called twice, - also in enqueue_scripts)
|
283 |
public static function getConfigForOptionsPage()
|
@@ -307,56 +367,7 @@ class Config
|
|
307 |
}
|
308 |
|
309 |
if ($config['operation-mode'] != 'no-conversion') {
|
310 |
-
|
311 |
-
$testResult = TestRun::getConverterStatus();
|
312 |
-
|
313 |
-
// Set "working" and "error" properties
|
314 |
-
if ($testResult) {
|
315 |
-
foreach ($config['converters'] as &$converter) {
|
316 |
-
$converterId = $converter['converter'];
|
317 |
-
$hasError = isset($testResult['errors'][$converterId]);
|
318 |
-
$working = !$hasError;
|
319 |
-
|
320 |
-
/*
|
321 |
-
Don't print this stuff here. It can end up in the head tag.
|
322 |
-
TODO: Move it somewhere
|
323 |
-
if (isset($converter['working']) && ($converter['working'] != $working)) {
|
324 |
-
|
325 |
-
// TODO: webpexpress_converterName($converterId)
|
326 |
-
if ($working) {
|
327 |
-
Messenger::printMessage(
|
328 |
-
'info',
|
329 |
-
'Hurray! - The <i>' . $converterId . '</i> conversion method is working now!'
|
330 |
-
);
|
331 |
-
} else {
|
332 |
-
Messenger::printMessage(
|
333 |
-
'warning',
|
334 |
-
'Sad news. The <i>' . $converterId . '</i> conversion method is not working anymore. What happened?'
|
335 |
-
);
|
336 |
-
}
|
337 |
-
}
|
338 |
-
*/
|
339 |
-
$converter['working'] = $working;
|
340 |
-
if ($hasError) {
|
341 |
-
$error = $testResult['errors'][$converterId];
|
342 |
-
if ($converterId == 'wpc') {
|
343 |
-
if (preg_match('/Missing URL/', $error)) {
|
344 |
-
$error = 'Not configured';
|
345 |
-
}
|
346 |
-
if ($error == 'No remote host has been set up') {
|
347 |
-
$error = 'Not configured';
|
348 |
-
}
|
349 |
-
|
350 |
-
if (preg_match('/cloud service is not enabled/', $error)) {
|
351 |
-
$error = 'The server is not enabled. Click the "Enable web service" on WebP Express settings on the site you are trying to connect to.';
|
352 |
-
}
|
353 |
-
}
|
354 |
-
$converter['error'] = $error;
|
355 |
-
} else {
|
356 |
-
unset($converter['error']);
|
357 |
-
}
|
358 |
-
}
|
359 |
-
}
|
360 |
}
|
361 |
|
362 |
self::$configForOptionsPage = $config; // cache the result
|
278 |
return self::fix(Config::loadConfig(), $checkQualityDetection);
|
279 |
}
|
280 |
|
281 |
+
/**
|
282 |
+
* Run a fresh test on all converters and update their statuses in the config.
|
283 |
+
*
|
284 |
+
* @param object config to be updated
|
285 |
+
* @return object Updated config
|
286 |
+
*/
|
287 |
+
public static function updateConverterStatusWithFreshTest($config) {
|
288 |
+
// Test converters
|
289 |
+
$testResult = TestRun::getConverterStatus();
|
290 |
+
|
291 |
+
// Set "working" and "error" properties
|
292 |
+
if ($testResult) {
|
293 |
+
foreach ($config['converters'] as &$converter) {
|
294 |
+
$converterId = $converter['converter'];
|
295 |
+
$hasError = isset($testResult['errors'][$converterId]);
|
296 |
+
$working = !$hasError;
|
297 |
+
|
298 |
+
/*
|
299 |
+
Don't print this stuff here. It can end up in the head tag.
|
300 |
+
TODO: Move it somewhere
|
301 |
+
if (isset($converter['working']) && ($converter['working'] != $working)) {
|
302 |
+
|
303 |
+
// TODO: webpexpress_converterName($converterId)
|
304 |
+
if ($working) {
|
305 |
+
Messenger::printMessage(
|
306 |
+
'info',
|
307 |
+
'Hurray! - The <i>' . $converterId . '</i> conversion method is working now!'
|
308 |
+
);
|
309 |
+
} else {
|
310 |
+
Messenger::printMessage(
|
311 |
+
'warning',
|
312 |
+
'Sad news. The <i>' . $converterId . '</i> conversion method is not working anymore. What happened?'
|
313 |
+
);
|
314 |
+
}
|
315 |
+
}
|
316 |
+
*/
|
317 |
+
$converter['working'] = $working;
|
318 |
+
if ($hasError) {
|
319 |
+
$error = $testResult['errors'][$converterId];
|
320 |
+
if ($converterId == 'wpc') {
|
321 |
+
if (preg_match('/Missing URL/', $error)) {
|
322 |
+
$error = 'Not configured';
|
323 |
+
}
|
324 |
+
if ($error == 'No remote host has been set up') {
|
325 |
+
$error = 'Not configured';
|
326 |
+
}
|
327 |
+
|
328 |
+
if (preg_match('/cloud service is not enabled/', $error)) {
|
329 |
+
$error = 'The server is not enabled. Click the "Enable web service" on WebP Express settings on the site you are trying to connect to.';
|
330 |
+
}
|
331 |
+
}
|
332 |
+
$converter['error'] = $error;
|
333 |
+
} else {
|
334 |
+
unset($converter['error']);
|
335 |
+
}
|
336 |
+
}
|
337 |
+
}
|
338 |
+
return $config;
|
339 |
+
}
|
340 |
+
|
341 |
|
342 |
public static $configForOptionsPage = null; // cache the result (called twice, - also in enqueue_scripts)
|
343 |
public static function getConfigForOptionsPage()
|
367 |
}
|
368 |
|
369 |
if ($config['operation-mode'] != 'no-conversion') {
|
370 |
+
$config = self::updateConverterStatusWithFreshTest($config);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
}
|
372 |
|
373 |
self::$configForOptionsPage = $config; // cache the result
|
lib/classes/ConvertHelperIndependent.php
CHANGED
@@ -571,7 +571,7 @@ APACHE
|
|
571 |
$text = preg_replace('#' . preg_quote($_SERVER["DOCUMENT_ROOT"]) . '#', '[doc-root]', $text);
|
572 |
|
573 |
// TODO: Put version number somewhere else. Ie \WebPExpress\VersionNumber::version
|
574 |
-
$text = 'WebP Express 0.
|
575 |
|
576 |
$logFile = self::getLogFilename($source, $logDir);
|
577 |
|
571 |
$text = preg_replace('#' . preg_quote($_SERVER["DOCUMENT_ROOT"]) . '#', '[doc-root]', $text);
|
572 |
|
573 |
// TODO: Put version number somewhere else. Ie \WebPExpress\VersionNumber::version
|
574 |
+
$text = 'WebP Express 0.19.0. ' . $msgTop . ', ' . date("Y-m-d H:i:s") . "\n\r\n\r" . $text;
|
575 |
|
576 |
$logFile = self::getLogFilename($source, $logDir);
|
577 |
|
lib/classes/ConvertersHelper.php
CHANGED
@@ -23,6 +23,10 @@ class ConvertersHelper
|
|
23 |
['converter' => 'graphicsmagick', 'options' => [
|
24 |
'use-nice' => true,
|
25 |
]],
|
|
|
|
|
|
|
|
|
26 |
['converter' => 'wpc', 'options' => []], // we should not set api-version default - it is handled in the javascript
|
27 |
['converter' => 'ewww', 'options' => []],
|
28 |
['converter' => 'imagick', 'options' => []],
|
@@ -63,7 +67,7 @@ class ConvertersHelper
|
|
63 |
}
|
64 |
|
65 |
/**
|
66 |
-
* Those converters in second, but not in first will be appended to first
|
67 |
*/
|
68 |
public static function mergeConverters($first, $second)
|
69 |
{
|
23 |
['converter' => 'graphicsmagick', 'options' => [
|
24 |
'use-nice' => true,
|
25 |
]],
|
26 |
+
['converter' => 'ffmpeg', 'options' => [
|
27 |
+
'use-nice' => true,
|
28 |
+
'method' => 4,
|
29 |
+
]],
|
30 |
['converter' => 'wpc', 'options' => []], // we should not set api-version default - it is handled in the javascript
|
31 |
['converter' => 'ewww', 'options' => []],
|
32 |
['converter' => 'imagick', 'options' => []],
|
67 |
}
|
68 |
|
69 |
/**
|
70 |
+
* Those converters in second array, but not in first will be appended to first
|
71 |
*/
|
72 |
public static function mergeConverters($first, $second)
|
73 |
{
|
lib/classes/DismissableGlobalMessages.php
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
use \WebPExpress\Option;
|
6 |
+
use \WebPExpress\State;
|
7 |
+
use \WebPExpress\Messenger;
|
8 |
+
|
9 |
+
class DismissableGlobalMessages
|
10 |
+
{
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Add dismissible message.
|
14 |
+
*
|
15 |
+
* @param string $id An identifier, ie "suggest_enable_pngs"
|
16 |
+
*/
|
17 |
+
public static function addDismissableMessage($id)
|
18 |
+
{
|
19 |
+
$dismissableGlobalMessageIds = State::getState('dismissableGlobalMessageIds', []);
|
20 |
+
|
21 |
+
// Ensure we do not add a message that is already there
|
22 |
+
if (in_array($id, $dismissableGlobalMessageIds)) {
|
23 |
+
return;
|
24 |
+
}
|
25 |
+
$dismissableGlobalMessageIds[] = $id;
|
26 |
+
State::setState('dismissableGlobalMessageIds', $dismissableGlobalMessageIds);
|
27 |
+
}
|
28 |
+
|
29 |
+
public static function printDismissableMessage($level, $msg, $id, $buttons)
|
30 |
+
{
|
31 |
+
$msg .= '<br><br>';
|
32 |
+
foreach ($buttons as $i => $button) {
|
33 |
+
$javascript = "jQuery(this).closest('div.notice').slideUp();";
|
34 |
+
//$javascript = "console.log(jQuery(this).closest('div.notice'));";
|
35 |
+
$javascript .= "jQuery.post(ajaxurl, " .
|
36 |
+
"{'action': 'webpexpress_dismiss_global_message', " .
|
37 |
+
"'id': '" . $id . "'})";
|
38 |
+
if (isset($button['javascript'])) {
|
39 |
+
$javascript .= ".done(function() {" . $button['javascript'] . "});";
|
40 |
+
}
|
41 |
+
if (isset($button['redirect-to-settings'])) {
|
42 |
+
$javascript .= ".done(function() {location.href='" . AdminUi::getSettingsUrl() . "'});";
|
43 |
+
}
|
44 |
+
|
45 |
+
$msg .= '<button type="button" class="button ' .
|
46 |
+
(($i == 0) ? 'button-primary' : '') .
|
47 |
+
'" onclick="' . $javascript . '" ' .
|
48 |
+
'style="display:inline-block; margin-top:20px; margin-right:20px; ' . (($i > 0) ? 'float:right;' : '') .
|
49 |
+
'">' . $button['text'] . '</button>';
|
50 |
+
|
51 |
+
}
|
52 |
+
Messenger::printMessage($level, $msg);
|
53 |
+
}
|
54 |
+
|
55 |
+
public static function printMessages()
|
56 |
+
{
|
57 |
+
$ids = State::getState('dismissableGlobalMessageIds', []);
|
58 |
+
foreach ($ids as $id) {
|
59 |
+
include_once __DIR__ . '/../dismissable-global-messages/' . $id . '.php';
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Dismiss message
|
65 |
+
*
|
66 |
+
* @param string $id An identifier, ie "suggest_enable_pngs"
|
67 |
+
*/
|
68 |
+
public static function dismissMessage($id) {
|
69 |
+
$messages = State::getState('dismissableGlobalMessageIds', []);
|
70 |
+
$newQueue = [];
|
71 |
+
foreach ($messages as $mid) {
|
72 |
+
if ($mid == $id) {
|
73 |
+
|
74 |
+
} else {
|
75 |
+
$newQueue[] = $mid;
|
76 |
+
}
|
77 |
+
}
|
78 |
+
State::setState('dismissableGlobalMessageIds', $newQueue);
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Dismiss message
|
83 |
+
*
|
84 |
+
* @param string $id An identifier, ie "suggest_enable_pngs"
|
85 |
+
*/
|
86 |
+
public static function dismissAll() {
|
87 |
+
State::setState('dismissableGlobalMessageIds', []);
|
88 |
+
}
|
89 |
+
|
90 |
+
public static function processAjaxDismissGlobalMessage() {
|
91 |
+
/*
|
92 |
+
We have no security nonce here
|
93 |
+
Dismissing a message is not harmful and dismissMessage($id) do anything harmful, no matter what you send in the "id"
|
94 |
+
*/
|
95 |
+
$id = sanitize_text_field($_POST['id']);
|
96 |
+
self::dismissMessage($id);
|
97 |
+
}
|
98 |
+
|
99 |
+
|
100 |
+
}
|
lib/dismissable-global-messages/0.19.0/meet-ffmpeg-a-working-conversion-method.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
$msgId = '0.19.0/meet-ffmpeg-a-working-conversion-method';
|
6 |
+
|
7 |
+
DismissableGlobalMessages::printDismissableMessage(
|
8 |
+
'success',
|
9 |
+
'Great news!<br><br> WebP Express 0.19.0 introduced a new conversion method: ffmpeg, which works on your system. ' .
|
10 |
+
'You now have a conversion method that works! To start using it, you must go to settings and click save.',
|
11 |
+
$msgId,
|
12 |
+
[
|
13 |
+
['text' => 'Take me to the settings', 'redirect-to-settings' => true],
|
14 |
+
['text' => 'Dismiss'],
|
15 |
+
]
|
16 |
+
);
|
lib/dismissable-global-messages/0.19.0/meet-ffmpeg-better-than-ewww.php
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
$msgId = '0.19.0/meet-ffmpeg-better-than-ewww';
|
6 |
+
|
7 |
+
DismissableGlobalMessages::printDismissableMessage(
|
8 |
+
'info',
|
9 |
+
'WebP Express 0.19.0 introduced a new conversion method: ffmpeg. ' .
|
10 |
+
'You may consider moving it above ewww, as ffmpeg supports the "Auto" WebP encoding option ' .
|
11 |
+
'(encoding to both lossy and lossless and then selecting the smallest)',
|
12 |
+
$msgId,
|
13 |
+
[
|
14 |
+
['text' => 'Take me to the settings', 'redirect-to-settings' => true],
|
15 |
+
['text' => 'Dismiss'],
|
16 |
+
]
|
17 |
+
);
|
lib/dismissable-global-messages/0.19.0/meet-ffmpeg-better-than-gd.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
$msgId = '0.19.0/meet-ffmpeg-better-than-gd';
|
6 |
+
|
7 |
+
DismissableGlobalMessages::printDismissableMessage(
|
8 |
+
'info',
|
9 |
+
'WebP Express 0.19.0 introduced a new conversion method: ffmpeg. ' .
|
10 |
+
'You may consider moving it above Gd, as it is slightly better. ',
|
11 |
+
$msgId,
|
12 |
+
[
|
13 |
+
['text' => 'Take me to the settings', 'redirect-to-settings' => true],
|
14 |
+
['text' => 'Dismiss'],
|
15 |
+
]
|
16 |
+
);
|
lib/migrate/migrate13.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
|
6 |
+
function webpexpress_migrate13_add_ffmpeg_message_if_relevant()
|
7 |
+
{
|
8 |
+
$config = Config::loadConfigAndFix(false); // false, because we do not need to test if quality detection is working
|
9 |
+
$config = Config::updateConverterStatusWithFreshTest($config); // Test all converters (especially we are excited to learn if the new ffmpeg converter is working)
|
10 |
+
|
11 |
+
$workingConverterIds = ConvertersHelper::getWorkingAndActiveConverterIds($config);
|
12 |
+
|
13 |
+
if (!in_array('ffmpeg', $workingConverterIds)) {
|
14 |
+
// ffmpeg is not working on the host, so no need to announce ffmpeg
|
15 |
+
return;
|
16 |
+
}
|
17 |
+
|
18 |
+
$betterConverterIds = ['cwebp', 'vips', 'imagemagick', 'graphicsmagick', 'imagick', 'gmagick', 'wpc'];
|
19 |
+
$workingAndBetter = array_intersect($workingConverterIds, $betterConverterIds);
|
20 |
+
|
21 |
+
if (count($workingAndBetter) > 0) {
|
22 |
+
// the user already has a better conversion method working. No reason to disturb
|
23 |
+
return;
|
24 |
+
}
|
25 |
+
|
26 |
+
if (in_array('gd', $workingConverterIds)) {
|
27 |
+
DismissableGlobalMessages::addDismissableMessage('0.19.0/meet-ffmpeg-better-than-gd');
|
28 |
+
} elseif (in_array('ewww', $workingConverterIds)) {
|
29 |
+
DismissableGlobalMessages::addDismissableMessage('0.19.0/meet-ffmpeg-better-than-ewww');
|
30 |
+
} else {
|
31 |
+
DismissableGlobalMessages::addDismissableMessage('0.19.0/meet-ffmpeg-a-working-conversion-method');
|
32 |
+
}
|
33 |
+
|
34 |
+
}
|
35 |
+
|
36 |
+
function webpexpress_migrate13() {
|
37 |
+
Option::updateOption('webp-express-migration-version', '13');
|
38 |
+
|
39 |
+
webpexpress_migrate13_add_ffmpeg_message_if_relevant();
|
40 |
+
}
|
41 |
+
|
42 |
+
webpexpress_migrate13();
|
lib/options/enqueue_scripts.php
CHANGED
@@ -6,7 +6,7 @@ use \WebPExpress\Paths;
|
|
6 |
use \WebPExpress\Config;
|
7 |
|
8 |
$ver = '6'; // note: Minimum 1
|
9 |
-
$jsDir = 'js/0.
|
10 |
|
11 |
if (!function_exists('webp_express_add_inline_script')) {
|
12 |
function webp_express_add_inline_script($id, $script, $position) {
|
6 |
use \WebPExpress\Config;
|
7 |
|
8 |
$ver = '6'; // note: Minimum 1
|
9 |
+
$jsDir = 'js/0.19.0'; // We change dir when it is critical that no-one gets the cached version (there is a plugin that strips version strings out there...)
|
10 |
|
11 |
if (!function_exists('webp_express_add_inline_script')) {
|
12 |
function webp_express_add_inline_script($id, $script, $position) {
|
lib/options/js/{0.16.0 → 0.19.0}/authorized_sites_bak.js
RENAMED
File without changes
|
lib/options/js/{0.16.0 → 0.19.0}/bulk-convert.js
RENAMED
File without changes
|
lib/options/js/{0.16.0 → 0.19.0}/converters.js
RENAMED
@@ -7,7 +7,7 @@ window.currentlyEditing = '';
|
|
7 |
|
8 |
function getConversionMethodDescription(converterId) {
|
9 |
var descriptions = {
|
10 |
-
'cwebp': '
|
11 |
'wpc': 'Remote WebP Express',
|
12 |
'ewww': 'ewww cloud converter',
|
13 |
'gd': 'Gd extension',
|
@@ -15,7 +15,8 @@ function getConversionMethodDescription(converterId) {
|
|
15 |
'gmagick': 'Gmagick (PHP extension)',
|
16 |
'imagemagick': 'ImageMagick',
|
17 |
'graphicsmagick': 'GraphicsMagick',
|
18 |
-
'vips': 'Vips'
|
|
|
19 |
};
|
20 |
|
21 |
if (descriptions[converterId]) {
|
@@ -71,7 +72,7 @@ function generateConverterHTML(converter) {
|
|
71 |
/* Set ids on global converters object */
|
72 |
function setTemporaryIdsOnConverters() {
|
73 |
if (window.converters == undefined) {
|
74 |
-
|
75 |
return;
|
76 |
}
|
77 |
var numConverterInstances = [];
|
@@ -305,7 +306,10 @@ function configureConverter(id) {
|
|
305 |
case 'vips':
|
306 |
document.getElementById('vips_smart_subsample').checked = getConverterOption(converter, 'smart-subsample', false);
|
307 |
document.getElementById('vips_preset').value = getConverterOption(converter, 'preset', 'disable');
|
308 |
-
|
|
|
|
|
|
|
309 |
break;
|
310 |
}
|
311 |
tb_show("Configure " + converter['id'] + ' converter', '#TB_inline?inlineId=' + converter['converter']);
|
@@ -396,6 +400,12 @@ function updateConverterOptions() {
|
|
396 |
setConverterOption(converter, 'preset', vipsPreset);
|
397 |
}
|
398 |
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
399 |
}
|
400 |
|
401 |
updateInputValue();
|
7 |
|
8 |
function getConversionMethodDescription(converterId) {
|
9 |
var descriptions = {
|
10 |
+
'cwebp': 'cwebp',
|
11 |
'wpc': 'Remote WebP Express',
|
12 |
'ewww': 'ewww cloud converter',
|
13 |
'gd': 'Gd extension',
|
15 |
'gmagick': 'Gmagick (PHP extension)',
|
16 |
'imagemagick': 'ImageMagick',
|
17 |
'graphicsmagick': 'GraphicsMagick',
|
18 |
+
'vips': 'Vips',
|
19 |
+
'ffmpeg': 'ffmpeg',
|
20 |
};
|
21 |
|
22 |
if (descriptions[converterId]) {
|
72 |
/* Set ids on global converters object */
|
73 |
function setTemporaryIdsOnConverters() {
|
74 |
if (window.converters == undefined) {
|
75 |
+
console.log('window.converters is undefined. Strange. Please report!');
|
76 |
return;
|
77 |
}
|
78 |
var numConverterInstances = [];
|
306 |
case 'vips':
|
307 |
document.getElementById('vips_smart_subsample').checked = getConverterOption(converter, 'smart-subsample', false);
|
308 |
document.getElementById('vips_preset').value = getConverterOption(converter, 'preset', 'disable');
|
309 |
+
break;
|
310 |
+
case 'ffmpeg':
|
311 |
+
document.getElementById('ffmpeg_use_nice').checked = getConverterOption(converter, 'use-nice', true);
|
312 |
+
document.getElementById('ffmpeg_method').value = getConverterOption(converter, 'method', '');
|
313 |
break;
|
314 |
}
|
315 |
tb_show("Configure " + converter['id'] + ' converter', '#TB_inline?inlineId=' + converter['converter']);
|
400 |
setConverterOption(converter, 'preset', vipsPreset);
|
401 |
}
|
402 |
break;
|
403 |
+
case 'ffmpeg':
|
404 |
+
setConverterOption(converter, 'use-nice', document.getElementById('ffmpeg_use_nice').checked);
|
405 |
+
var methodString = document.getElementById('ffmpeg_method').value;
|
406 |
+
var methodNum = (methodString == '') ? 6 : parseInt(methodString, 10);
|
407 |
+
setConverterOption(converter, 'method', methodNum);
|
408 |
+
break;
|
409 |
}
|
410 |
|
411 |
updateInputValue();
|
lib/options/js/{0.16.0 → 0.19.0}/das-popup.js
RENAMED
File without changes
|
lib/options/js/{0.16.0 → 0.19.0}/escapeHTML.js
RENAMED
File without changes
|
lib/options/js/{0.16.0 → 0.19.0}/image-comparison-slider.js
RENAMED
File without changes
|
lib/options/js/{0.16.0 → 0.19.0}/page.js
RENAMED
File without changes
|
lib/options/js/{0.16.0 → 0.19.0}/purge-cache.js
RENAMED
File without changes
|
lib/options/js/{0.16.0 → 0.19.0}/self-test.js
RENAMED
File without changes
|
lib/options/js/{0.16.0 → 0.19.0}/sortable.min.js
RENAMED
File without changes
|
lib/options/js/{0.16.0 → 0.19.0}/test-convert.js
RENAMED
File without changes
|
lib/options/js/{0.16.0 → 0.19.0}/whitelist.js
RENAMED
@@ -1,6 +1,6 @@
|
|
1 |
function updateWhitelistInputValue() {
|
2 |
if (document.getElementById('whitelist') == null) {
|
3 |
-
|
4 |
return;
|
5 |
}
|
6 |
document.getElementById('whitelist').value = JSON.stringify(window.whitelist);
|
1 |
function updateWhitelistInputValue() {
|
2 |
if (document.getElementById('whitelist') == null) {
|
3 |
+
console.log('document.getElementById("whitelist") returns null. Strange! Please report.');
|
4 |
return;
|
5 |
}
|
6 |
document.getElementById('whitelist').value = JSON.stringify(window.whitelist);
|
lib/options/options/conversion-options/converter-options/ffmpeg.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div id="ffmpeg" style="display:none;">
|
2 |
+
<div class="ffmpeg converter-options">
|
3 |
+
<h3>ffmpeg options</h3>
|
4 |
+
<p>This conversion method works by executing ffmpeg binary.</p>
|
5 |
+
|
6 |
+
<div>
|
7 |
+
<label for="ffmpeg_use_nice">
|
8 |
+
Use nice
|
9 |
+
<?php echo helpIcon(
|
10 |
+
'Enabling this option saves system resources at the cost of slightly slower conversion.'
|
11 |
+
); ?>
|
12 |
+
</label>
|
13 |
+
<input type="checkbox" id="ffmpeg_use_nice">
|
14 |
+
</div>
|
15 |
+
<div>
|
16 |
+
<label for="ffmpeg_method">Method (0-6)</label>
|
17 |
+
<input type="text" size="2" id="ffmpeg_method">
|
18 |
+
<br>This parameter controls the trade off between encoding speed and the compressed file size and quality.
|
19 |
+
Possible values range from 0 to 6. 0 is fastest. 6 results in best quality.
|
20 |
+
</div>
|
21 |
+
<br>
|
22 |
+
<?php
|
23 |
+
/*
|
24 |
+
Removed (#243)
|
25 |
+
if (!$canDetectQuality) {
|
26 |
+
printAutoQualityOptionForConverter('imagemagick');
|
27 |
+
}*/
|
28 |
+
?>
|
29 |
+
<!--
|
30 |
+
<button onclick="updateConverterOptions()" class="button button-primary" type="button">Update</button>
|
31 |
+
-->
|
32 |
+
<!-- <a href="javascript: tb_remove();">close</a> -->
|
33 |
+
<?php webp_express_printUpdateButtons() ?>
|
34 |
+
</div>
|
35 |
+
</div>
|
lib/options/options/conversion-options/converters.inc
CHANGED
@@ -32,6 +32,7 @@
|
|
32 |
include 'converter-options/wpc.php';
|
33 |
include 'converter-options/imagemagick.php';
|
34 |
include 'converter-options/graphicsmagick.php';
|
|
|
35 |
?>
|
36 |
</td>
|
37 |
</tr>
|
32 |
include 'converter-options/wpc.php';
|
33 |
include 'converter-options/imagemagick.php';
|
34 |
include 'converter-options/graphicsmagick.php';
|
35 |
+
include 'converter-options/ffmpeg.php';
|
36 |
?>
|
37 |
</td>
|
38 |
</tr>
|
lib/options/page-messages.php
CHANGED
@@ -14,6 +14,7 @@ use \WebPExpress\Paths;
|
|
14 |
use \WebPExpress\PlatformInfo;
|
15 |
use \WebPExpress\State;
|
16 |
|
|
|
17 |
// TODO: Move most of this file into a ProblemDetector class (SystemHealth)
|
18 |
|
19 |
if (!(State::getState('configured', false))) {
|
14 |
use \WebPExpress\PlatformInfo;
|
15 |
use \WebPExpress\State;
|
16 |
|
17 |
+
|
18 |
// TODO: Move most of this file into a ProblemDetector class (SystemHealth)
|
19 |
|
20 |
if (!(State::getState('configured', false))) {
|
lib/options/page-welcome.php
CHANGED
@@ -32,7 +32,7 @@ if ($weKnowThereAreNoWorkingConverters) {
|
|
32 |
'<li>You can purchase a key for the <a target="_blank" href="https://ewww.io/plans/">ewww cloud converter</a>. They do not charge credits for webp conversions, so all you ever have to pay is the one dollar start-up fee :)</li>' .
|
33 |
'<li>I have written a <a target="_blank" href="https://github.com/rosell-dk/webp-convert/wiki/A-template-letter-for-shared-hosts">template letter</a> which you can try sending to your webhost</li>' .
|
34 |
'<li>You can set up a <a target="_blank" href="https://github.com/rosell-dk/webp-convert-cloud-service">webp-convert-cloud-service</a> on another server and connect to that. Its open source.</li>' .
|
35 |
-
'<li>You can try to meet the server requirements of cwebp, imagick, vips, gmagick or gd. Check out <a target="_blank" href="https://github.com/rosell-dk/webp-convert/wiki/Meeting-the-requirements-of-the-converters">this wiki page</a> on how to do that</li>' .
|
36 |
'</ol>' .
|
37 |
'<p>Of course, there is also the option of using another plugin altogether. ' .
|
38 |
'I can recommend <i>Optimole</i>. ' .
|
32 |
'<li>You can purchase a key for the <a target="_blank" href="https://ewww.io/plans/">ewww cloud converter</a>. They do not charge credits for webp conversions, so all you ever have to pay is the one dollar start-up fee :)</li>' .
|
33 |
'<li>I have written a <a target="_blank" href="https://github.com/rosell-dk/webp-convert/wiki/A-template-letter-for-shared-hosts">template letter</a> which you can try sending to your webhost</li>' .
|
34 |
'<li>You can set up a <a target="_blank" href="https://github.com/rosell-dk/webp-convert-cloud-service">webp-convert-cloud-service</a> on another server and connect to that. Its open source.</li>' .
|
35 |
+
'<li>You can try to meet the server requirements of cwebp, imagick, vips, gmagick, ffmpeg or gd. Check out <a target="_blank" href="https://github.com/rosell-dk/webp-convert/wiki/Meeting-the-requirements-of-the-converters">this wiki page</a> on how to do that</li>' .
|
36 |
'</ol>' .
|
37 |
'<p>Of course, there is also the option of using another plugin altogether. ' .
|
38 |
'I can recommend <i>Optimole</i>. ' .
|
vendor/composer/autoload_classmap.php
CHANGED
@@ -137,6 +137,8 @@ return array(
|
|
137 |
'ImageMimeTypeGuesser\\Detectors\\Stack' => $vendorDir . '/rosell-dk/image-mime-type-guesser/src/Detectors/Stack.php',
|
138 |
'ImageMimeTypeGuesser\\GuessFromExtension' => $vendorDir . '/rosell-dk/image-mime-type-guesser/src/GuessFromExtension.php',
|
139 |
'ImageMimeTypeGuesser\\ImageMimeTypeGuesser' => $vendorDir . '/rosell-dk/image-mime-type-guesser/src/ImageMimeTypeGuesser.php',
|
|
|
|
|
140 |
'WebPConvertCloudService\\AccessCheck' => $vendorDir . '/rosell-dk/webp-convert-cloud-service/src/AccessCheck.php',
|
141 |
'WebPConvertCloudService\\Serve' => $vendorDir . '/rosell-dk/webp-convert-cloud-service/src/Serve.php',
|
142 |
'WebPConvertCloudService\\WebPConvertCloudService' => $vendorDir . '/rosell-dk/webp-convert-cloud-service/src/WebPConvertCloudService.php',
|
@@ -153,6 +155,7 @@ return array(
|
|
153 |
'WebPConvert\\Convert\\Converters\\ConverterTraits\\ExecTrait' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/ConverterTraits/ExecTrait.php',
|
154 |
'WebPConvert\\Convert\\Converters\\Cwebp' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/Cwebp.php',
|
155 |
'WebPConvert\\Convert\\Converters\\Ewww' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/Ewww.php',
|
|
|
156 |
'WebPConvert\\Convert\\Converters\\Gd' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/Gd.php',
|
157 |
'WebPConvert\\Convert\\Converters\\Gmagick' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/Gmagick.php',
|
158 |
'WebPConvert\\Convert\\Converters\\GmagickBinary' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/GmagickBinary.php',
|
137 |
'ImageMimeTypeGuesser\\Detectors\\Stack' => $vendorDir . '/rosell-dk/image-mime-type-guesser/src/Detectors/Stack.php',
|
138 |
'ImageMimeTypeGuesser\\GuessFromExtension' => $vendorDir . '/rosell-dk/image-mime-type-guesser/src/GuessFromExtension.php',
|
139 |
'ImageMimeTypeGuesser\\ImageMimeTypeGuesser' => $vendorDir . '/rosell-dk/image-mime-type-guesser/src/ImageMimeTypeGuesser.php',
|
140 |
+
'Onnov\\DetectEncoding\\CodePage' => $vendorDir . '/onnov/detect-encoding/src/CodePage.php',
|
141 |
+
'Onnov\\DetectEncoding\\EncodingDetector' => $vendorDir . '/onnov/detect-encoding/src/EncodingDetector.php',
|
142 |
'WebPConvertCloudService\\AccessCheck' => $vendorDir . '/rosell-dk/webp-convert-cloud-service/src/AccessCheck.php',
|
143 |
'WebPConvertCloudService\\Serve' => $vendorDir . '/rosell-dk/webp-convert-cloud-service/src/Serve.php',
|
144 |
'WebPConvertCloudService\\WebPConvertCloudService' => $vendorDir . '/rosell-dk/webp-convert-cloud-service/src/WebPConvertCloudService.php',
|
155 |
'WebPConvert\\Convert\\Converters\\ConverterTraits\\ExecTrait' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/ConverterTraits/ExecTrait.php',
|
156 |
'WebPConvert\\Convert\\Converters\\Cwebp' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/Cwebp.php',
|
157 |
'WebPConvert\\Convert\\Converters\\Ewww' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/Ewww.php',
|
158 |
+
'WebPConvert\\Convert\\Converters\\FFMpeg' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/FFMpeg.php',
|
159 |
'WebPConvert\\Convert\\Converters\\Gd' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/Gd.php',
|
160 |
'WebPConvert\\Convert\\Converters\\Gmagick' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/Gmagick.php',
|
161 |
'WebPConvert\\Convert\\Converters\\GmagickBinary' => $vendorDir . '/rosell-dk/webp-convert/src/Convert/Converters/GmagickBinary.php',
|
vendor/composer/autoload_psr4.php
CHANGED
@@ -8,6 +8,7 @@ $baseDir = dirname($vendorDir);
|
|
8 |
return array(
|
9 |
'WebPConvert\\' => array($vendorDir . '/rosell-dk/webp-convert/src'),
|
10 |
'WebPConvertCloudService\\' => array($vendorDir . '/rosell-dk/webp-convert-cloud-service/src'),
|
|
|
11 |
'ImageMimeTypeGuesser\\' => array($vendorDir . '/rosell-dk/image-mime-type-guesser/src'),
|
12 |
'HtaccessCapabilityTester\\' => array($vendorDir . '/rosell-dk/htaccess-capability-tester/src'),
|
13 |
'DOMUtilForWebP\\' => array($vendorDir . '/rosell-dk/dom-util-for-webp/src'),
|
8 |
return array(
|
9 |
'WebPConvert\\' => array($vendorDir . '/rosell-dk/webp-convert/src'),
|
10 |
'WebPConvertCloudService\\' => array($vendorDir . '/rosell-dk/webp-convert-cloud-service/src'),
|
11 |
+
'Onnov\\DetectEncoding\\' => array($vendorDir . '/onnov/detect-encoding/src'),
|
12 |
'ImageMimeTypeGuesser\\' => array($vendorDir . '/rosell-dk/image-mime-type-guesser/src'),
|
13 |
'HtaccessCapabilityTester\\' => array($vendorDir . '/rosell-dk/htaccess-capability-tester/src'),
|
14 |
'DOMUtilForWebP\\' => array($vendorDir . '/rosell-dk/dom-util-for-webp/src'),
|
vendor/composer/autoload_static.php
CHANGED
@@ -12,6 +12,10 @@ class ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243
|
|
12 |
'WebPConvert\\' => 12,
|
13 |
'WebPConvertCloudService\\' => 24,
|
14 |
),
|
|
|
|
|
|
|
|
|
15 |
'I' =>
|
16 |
array (
|
17 |
'ImageMimeTypeGuesser\\' => 21,
|
@@ -39,6 +43,10 @@ class ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243
|
|
39 |
array (
|
40 |
0 => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src',
|
41 |
),
|
|
|
|
|
|
|
|
|
42 |
'ImageMimeTypeGuesser\\' =>
|
43 |
array (
|
44 |
0 => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src',
|
@@ -189,6 +197,8 @@ class ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243
|
|
189 |
'ImageMimeTypeGuesser\\Detectors\\Stack' => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src/Detectors/Stack.php',
|
190 |
'ImageMimeTypeGuesser\\GuessFromExtension' => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src/GuessFromExtension.php',
|
191 |
'ImageMimeTypeGuesser\\ImageMimeTypeGuesser' => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src/ImageMimeTypeGuesser.php',
|
|
|
|
|
192 |
'WebPConvertCloudService\\AccessCheck' => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src/AccessCheck.php',
|
193 |
'WebPConvertCloudService\\Serve' => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src/Serve.php',
|
194 |
'WebPConvertCloudService\\WebPConvertCloudService' => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src/WebPConvertCloudService.php',
|
@@ -205,6 +215,7 @@ class ComposerStaticInit16597e36dd1bfcd787ed5a8e6d908243
|
|
205 |
'WebPConvert\\Convert\\Converters\\ConverterTraits\\ExecTrait' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/ConverterTraits/ExecTrait.php',
|
206 |
'WebPConvert\\Convert\\Converters\\Cwebp' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/Cwebp.php',
|
207 |
'WebPConvert\\Convert\\Converters\\Ewww' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/Ewww.php',
|
|
|
208 |
'WebPConvert\\Convert\\Converters\\Gd' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/Gd.php',
|
209 |
'WebPConvert\\Convert\\Converters\\Gmagick' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/Gmagick.php',
|
210 |
'WebPConvert\\Convert\\Converters\\GmagickBinary' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/GmagickBinary.php',
|
12 |
'WebPConvert\\' => 12,
|
13 |
'WebPConvertCloudService\\' => 24,
|
14 |
),
|
15 |
+
'O' =>
|
16 |
+
array (
|
17 |
+
'Onnov\\DetectEncoding\\' => 21,
|
18 |
+
),
|
19 |
'I' =>
|
20 |
array (
|
21 |
'ImageMimeTypeGuesser\\' => 21,
|
43 |
array (
|
44 |
0 => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src',
|
45 |
),
|
46 |
+
'Onnov\\DetectEncoding\\' =>
|
47 |
+
array (
|
48 |
+
0 => __DIR__ . '/..' . '/onnov/detect-encoding/src',
|
49 |
+
),
|
50 |
'ImageMimeTypeGuesser\\' =>
|
51 |
array (
|
52 |
0 => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src',
|
197 |
'ImageMimeTypeGuesser\\Detectors\\Stack' => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src/Detectors/Stack.php',
|
198 |
'ImageMimeTypeGuesser\\GuessFromExtension' => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src/GuessFromExtension.php',
|
199 |
'ImageMimeTypeGuesser\\ImageMimeTypeGuesser' => __DIR__ . '/..' . '/rosell-dk/image-mime-type-guesser/src/ImageMimeTypeGuesser.php',
|
200 |
+
'Onnov\\DetectEncoding\\CodePage' => __DIR__ . '/..' . '/onnov/detect-encoding/src/CodePage.php',
|
201 |
+
'Onnov\\DetectEncoding\\EncodingDetector' => __DIR__ . '/..' . '/onnov/detect-encoding/src/EncodingDetector.php',
|
202 |
'WebPConvertCloudService\\AccessCheck' => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src/AccessCheck.php',
|
203 |
'WebPConvertCloudService\\Serve' => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src/Serve.php',
|
204 |
'WebPConvertCloudService\\WebPConvertCloudService' => __DIR__ . '/..' . '/rosell-dk/webp-convert-cloud-service/src/WebPConvertCloudService.php',
|
215 |
'WebPConvert\\Convert\\Converters\\ConverterTraits\\ExecTrait' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/ConverterTraits/ExecTrait.php',
|
216 |
'WebPConvert\\Convert\\Converters\\Cwebp' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/Cwebp.php',
|
217 |
'WebPConvert\\Convert\\Converters\\Ewww' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/Ewww.php',
|
218 |
+
'WebPConvert\\Convert\\Converters\\FFMpeg' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/FFMpeg.php',
|
219 |
'WebPConvert\\Convert\\Converters\\Gd' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/Gd.php',
|
220 |
'WebPConvert\\Convert\\Converters\\Gmagick' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/Gmagick.php',
|
221 |
'WebPConvert\\Convert\\Converters\\GmagickBinary' => __DIR__ . '/..' . '/rosell-dk/webp-convert/src/Convert/Converters/GmagickBinary.php',
|
vendor/composer/installed.json
CHANGED
@@ -128,6 +128,68 @@
|
|
128 |
"zikula"
|
129 |
]
|
130 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
{
|
132 |
"name": "rosell-dk/dom-util-for-webp",
|
133 |
"version": "0.4.0",
|
@@ -309,17 +371,17 @@
|
|
309 |
},
|
310 |
{
|
311 |
"name": "rosell-dk/webp-convert",
|
312 |
-
"version": "2.
|
313 |
-
"version_normalized": "2.
|
314 |
"source": {
|
315 |
"type": "git",
|
316 |
"url": "https://github.com/rosell-dk/webp-convert.git",
|
317 |
-
"reference": "
|
318 |
},
|
319 |
"dist": {
|
320 |
"type": "zip",
|
321 |
-
"url": "https://api.github.com/repos/rosell-dk/webp-convert/zipball/
|
322 |
-
"reference": "
|
323 |
"shasum": ""
|
324 |
},
|
325 |
"require": {
|
@@ -337,7 +399,7 @@
|
|
337 |
"ext-vips": "to use Vips extension for converting.",
|
338 |
"php-stan/php-stan": "Suggested for dev, in order to analyse code before committing"
|
339 |
},
|
340 |
-
"time": "2020-
|
341 |
"type": "library",
|
342 |
"extra": {
|
343 |
"scripts-descriptions": {
|
128 |
"zikula"
|
129 |
]
|
130 |
},
|
131 |
+
{
|
132 |
+
"name": "onnov/detect-encoding",
|
133 |
+
"version": "v1.2.0",
|
134 |
+
"version_normalized": "1.2.0.0",
|
135 |
+
"source": {
|
136 |
+
"type": "git",
|
137 |
+
"url": "https://github.com/onnov/detect-encoding.git",
|
138 |
+
"reference": "c88cea4f0c83d7f7e0675f2801e0995f328de1ce"
|
139 |
+
},
|
140 |
+
"dist": {
|
141 |
+
"type": "zip",
|
142 |
+
"url": "https://api.github.com/repos/onnov/detect-encoding/zipball/c88cea4f0c83d7f7e0675f2801e0995f328de1ce",
|
143 |
+
"reference": "c88cea4f0c83d7f7e0675f2801e0995f328de1ce",
|
144 |
+
"shasum": ""
|
145 |
+
},
|
146 |
+
"require": {
|
147 |
+
"ext-iconv": "*",
|
148 |
+
"php": ">=7.2"
|
149 |
+
},
|
150 |
+
"require-dev": {
|
151 |
+
"infection/infection": "*",
|
152 |
+
"phpbench/phpbench": "*",
|
153 |
+
"phpcompatibility/php-compatibility": "*",
|
154 |
+
"phpmd/phpmd": "*",
|
155 |
+
"phpstan/phpstan": "*",
|
156 |
+
"phpstan/phpstan-strict-rules": "*",
|
157 |
+
"phpunit/phpunit": "*",
|
158 |
+
"roave/backward-compatibility-check": "*",
|
159 |
+
"squizlabs/php_codesniffer": "*"
|
160 |
+
},
|
161 |
+
"time": "2019-09-20T16:11:46+00:00",
|
162 |
+
"type": "library",
|
163 |
+
"installation-source": "dist",
|
164 |
+
"autoload": {
|
165 |
+
"psr-4": {
|
166 |
+
"Onnov\\DetectEncoding\\": "src/"
|
167 |
+
}
|
168 |
+
},
|
169 |
+
"notification-url": "https://packagist.org/downloads/",
|
170 |
+
"license": [
|
171 |
+
"MIT"
|
172 |
+
],
|
173 |
+
"authors": [
|
174 |
+
{
|
175 |
+
"name": "onnov",
|
176 |
+
"email": "oblnn@yandex.ru"
|
177 |
+
}
|
178 |
+
],
|
179 |
+
"description": "Text encoding definition class instead of mb_detect_encoding. Defines: utf-8, windows-1251, koi8-r, iso-8859-5, ibm866, .....",
|
180 |
+
"homepage": "https://github.com/onnov/detect-encoding",
|
181 |
+
"keywords": [
|
182 |
+
"cyrillic",
|
183 |
+
"encoding",
|
184 |
+
"ibm866",
|
185 |
+
"iconv",
|
186 |
+
"iso-8859-5",
|
187 |
+
"koi8-r",
|
188 |
+
"mb_detect_encoding",
|
189 |
+
"utf-8",
|
190 |
+
"windows-1251"
|
191 |
+
]
|
192 |
+
},
|
193 |
{
|
194 |
"name": "rosell-dk/dom-util-for-webp",
|
195 |
"version": "0.4.0",
|
371 |
},
|
372 |
{
|
373 |
"name": "rosell-dk/webp-convert",
|
374 |
+
"version": "2.4.0",
|
375 |
+
"version_normalized": "2.4.0.0",
|
376 |
"source": {
|
377 |
"type": "git",
|
378 |
"url": "https://github.com/rosell-dk/webp-convert.git",
|
379 |
+
"reference": "187a578ee55730f7a128a2f07b4351524b10d47b"
|
380 |
},
|
381 |
"dist": {
|
382 |
"type": "zip",
|
383 |
+
"url": "https://api.github.com/repos/rosell-dk/webp-convert/zipball/187a578ee55730f7a128a2f07b4351524b10d47b",
|
384 |
+
"reference": "187a578ee55730f7a128a2f07b4351524b10d47b",
|
385 |
"shasum": ""
|
386 |
},
|
387 |
"require": {
|
399 |
"ext-vips": "to use Vips extension for converting.",
|
400 |
"php-stan/php-stan": "Suggested for dev, in order to analyse code before committing"
|
401 |
},
|
402 |
+
"time": "2020-11-10T11:24:50+00:00",
|
403 |
"type": "library",
|
404 |
"extra": {
|
405 |
"scripts-descriptions": {
|
vendor/onnov/detect-encoding/.travis.yml
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
language: php
|
2 |
+
sudo: false
|
3 |
+
dist: trusty
|
4 |
+
|
5 |
+
cache:
|
6 |
+
directories:
|
7 |
+
- $HOME/.cache/composer/files
|
8 |
+
|
9 |
+
php:
|
10 |
+
- '7.2'
|
11 |
+
- '7.3'
|
12 |
+
|
13 |
+
matrix:
|
14 |
+
fast_finish: true
|
15 |
+
include:
|
16 |
+
- php: 7.4snapshot
|
17 |
+
env: NO_INFECTION=1
|
18 |
+
- php: nightly
|
19 |
+
env: NO_INFECTION=1
|
20 |
+
|
21 |
+
before_install:
|
22 |
+
- if [[ $NO_XDEBUG == 1 ]]; then phpenv config-rm xdebug.ini || echo 'No xdebug config.'; fi
|
23 |
+
- test "$TRAVIS_PHP_VERSION" != "nightly" || export COMPOSER_FLAGS="$COMPOSER_FLAGS --ignore-platform-reqs"
|
24 |
+
|
25 |
+
before_script:
|
26 |
+
- composer self-update
|
27 |
+
- COMPOSER_MEMORY_LIMIT=-1 travis_retry composer install --prefer-dist $COMPOSER_FLAGS
|
28 |
+
|
29 |
+
script:
|
30 |
+
- composer validate --no-check-all
|
31 |
+
- composer phpcs
|
32 |
+
- composer phpmd
|
33 |
+
- composer phpstan
|
34 |
+
- if [[ $NO_INFECTION != 1 ]]; then composer infection; fi
|
35 |
+
- composer coverage
|
36 |
+
|
37 |
+
notifications:
|
38 |
+
email: false
|
vendor/onnov/detect-encoding/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2019 onnov
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
vendor/onnov/detect-encoding/README.md
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[![Build Status](https://travis-ci.org/onnov/detect-encoding.svg?branch=master)](https://travis-ci.org/onnov/detect-encoding)
|
2 |
+
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/onnov/detect-encoding/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/onnov/detect-encoding/?branch=master)
|
3 |
+
[![Code Coverage](https://scrutinizer-ci.com/g/onnov/detect-encoding/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/onnov/detect-encoding/?branch=master)
|
4 |
+
[![Latest Stable Version](https://poser.pugx.org/onnov/detect-encoding/v/stable)](https://packagist.org/packages/onnov/detect-encoding)
|
5 |
+
[![License](https://poser.pugx.org/onnov/detect-encoding/license)](https://packagist.org/packages/onnov/detect-encoding)
|
6 |
+
|
7 |
+
# Detect encoding
|
8 |
+
|
9 |
+
Text encoding definition class based on a range of code page character numbers.
|
10 |
+
|
11 |
+
So far, in PHP v7.* the `mb_detect_encoding` function does not work well.
|
12 |
+
Therefore, you have to somehow solve this problem.
|
13 |
+
This class is one solution.
|
14 |
+
|
15 |
+
Built-in encodings and accuracy:
|
16 |
+
|
17 |
+
letters -> | 5 | 15 | 30 | 60 | 120 | 180 | 270
|
18 |
+
--- | --- | --- | --- |--- |--- |--- |---
|
19 |
+
windows-1251 | 99.13 | 98.83 | 98.54 | 99.04 | 99.73 | 99.93 | 100.0
|
20 |
+
koi8-r | 99.89 | 99.98 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0
|
21 |
+
iso-8859-5 | 81.79 | 99.27 | 99.98 | 100.0 | 100.0 | 100.0 | 100.0
|
22 |
+
ibm866 | 99.81 | 99.99 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0
|
23 |
+
mac-cyrillic | 12.79 | 47.49 | 73.48 | 92.15 | 99.30 | 99.94 | 100.0
|
24 |
+
|
25 |
+
Worst accuracy with mac-cyrillic, you need at least 60 characters to determine this encoding with an accuracy of 92.15%. Windows-1251 encoding also has very poor accuracy. This is because the numbers of their characters in the tables overlap very much.
|
26 |
+
|
27 |
+
Fortunately, mac-cyrillic and ibm866 encodings are not used to encode web pages. By default, they are disabled in the script, but you can enable them if necessary.
|
28 |
+
|
29 |
+
letters -> | 5 | 10 | 15 | 30 | 60 |
|
30 |
+
--- | --- | --- | --- |--- |--- |
|
31 |
+
windows-1251 | 99.40 | 99.69 | 99.86 | 99.97 | 100.0 |
|
32 |
+
koi8-r | 99.89 | 99.98 | 99.98 | 100.0 | 100.0 |
|
33 |
+
iso-8859-5 | 81.79 | 96.41 | 99.27 | 99.98 | 100.0 |
|
34 |
+
|
35 |
+
The accuracy of the determination is high even in short sentences from 5 to 10 letters. And for phrases from 60 letters, the accuracy of determination reaches 100%.
|
36 |
+
|
37 |
+
Determining the encoding is very fast, for example, text longer than 1,300,000 Cyrillic characters is checked in 0.00096 sec. (on my computer)
|
38 |
+
|
39 |
+
Link to the idea: http://patttern.blogspot.com/2012/07/php-python.html
|
40 |
+
|
41 |
+
## Installation
|
42 |
+
[Composer](https://getcomposer.org) (recommended)
|
43 |
+
Use Composer to install this library from Packagist: onnov/captcha
|
44 |
+
|
45 |
+
Run the following command from your project directory to add the dependency:
|
46 |
+
```bash
|
47 |
+
composer require onnov/detect-encoding
|
48 |
+
```
|
49 |
+
|
50 |
+
Alternatively, add the dependency directly to your composer.json file:
|
51 |
+
```json
|
52 |
+
{
|
53 |
+
"require": {
|
54 |
+
"onnov/detect-encoding": "^1.0"
|
55 |
+
}
|
56 |
+
}
|
57 |
+
```
|
58 |
+
|
59 |
+
The classes in the project are structured according to the PSR-4 standard, so you can also use your own autoloader or require the needed files directly in your code.
|
60 |
+
|
61 |
+
## Usage
|
62 |
+
```php
|
63 |
+
use Onnov\DetectEncoding\EncodingDetector;
|
64 |
+
|
65 |
+
$detector = new EncodingDetector();
|
66 |
+
```
|
67 |
+
|
68 |
+
* Definition of text encoding:
|
69 |
+
```php
|
70 |
+
$text = 'Проверяемый текст';
|
71 |
+
$detector->getEncoding($text)
|
72 |
+
```
|
73 |
+
|
74 |
+
* Method for converting text of an unknown encoding into a given encoding, by default in utf-8
|
75 |
+
optional parameters:
|
76 |
+
```php
|
77 |
+
/**
|
78 |
+
* Method for converting text of an unknown encoding into a given encoding, by default in utf-8
|
79 |
+
* optional parameters:
|
80 |
+
* $extra = '//TRANSLIT' (default setting) , other options: '' or '//IGNORE'
|
81 |
+
* $encoding = 'utf-8' (default setting) , other options: any encoding that is available iconv
|
82 |
+
*
|
83 |
+
* @param string $text
|
84 |
+
* @param string $extra
|
85 |
+
* @param string $encoding
|
86 |
+
*
|
87 |
+
* @return string
|
88 |
+
* @throws RuntimeException
|
89 |
+
*/
|
90 |
+
|
91 |
+
$detector->iconvXtoEncoding($text)
|
92 |
+
```
|
93 |
+
|
94 |
+
* Method to enable encoding definition:
|
95 |
+
```php
|
96 |
+
$detector->enableEncoding([
|
97 |
+
$detector::IBM866,
|
98 |
+
$detector::MAC_CYRILLIC,
|
99 |
+
]);
|
100 |
+
```
|
101 |
+
|
102 |
+
* Method to disable encoding definition:
|
103 |
+
```php
|
104 |
+
$detector->disableEncoding([
|
105 |
+
$detector::ISO_8859_5,
|
106 |
+
]);
|
107 |
+
```
|
108 |
+
|
109 |
+
* Method for adding custom encoding:
|
110 |
+
```php
|
111 |
+
$detector->addEncoding([
|
112 |
+
'encodingName' => [
|
113 |
+
'upper' => '1-50,200-250,253', // uppercase character number range
|
114 |
+
'lower' => '55-100,120-180,199', // lowercase character number range
|
115 |
+
],
|
116 |
+
]);
|
117 |
+
```
|
118 |
+
|
119 |
+
* Method to get a custom encoding range:
|
120 |
+
```php
|
121 |
+
use Onnov\DetectEncoding\CodePage;
|
122 |
+
|
123 |
+
// utf-8 encoded alphabet
|
124 |
+
$cyrillicUppercase = 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФЧЦЧШЩЪЫЬЭЮЯ';
|
125 |
+
$cyrillicLowercase = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя';
|
126 |
+
|
127 |
+
$codePage = new CodePage();
|
128 |
+
$encodingRange = $codePage->getRange($cyrillicUppercase, $cyrillicLowercase, 'koi8-u'));
|
129 |
+
```
|
130 |
+
|
131 |
+
## Symfony use
|
132 |
+
Add in services.yaml file:
|
133 |
+
```yaml
|
134 |
+
services:
|
135 |
+
Onnov\DetectEncoding\EncodingDetector:
|
136 |
+
autowire: true
|
137 |
+
```
|
vendor/onnov/detect-encoding/bin/testsRun.sh
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env bash
|
2 |
+
|
3 |
+
vendor/bin/phpcs
|
4 |
+
vendor/bin/phpmd src text cleancode,codesize,controversial,design,naming,unusedcode
|
5 |
+
vendor/bin/phpstan analyse src/ -c phpstan.neon --level=7 --no-progress -vvv --memory-limit=-1
|
6 |
+
vendor/bin/phpbench run benchmarks --report=default
|
7 |
+
vendor/bin/infection --min-msi=50 --min-covered-msi=70 --log-verbosity=all
|
8 |
+
vendor/bin/phpunit --coverage-text --coverage-html ./build/coverage/html --coverage-clover ./build/coverage/clover.xml
|
vendor/onnov/detect-encoding/composer.json
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "onnov/detect-encoding",
|
3 |
+
"description": "Text encoding definition class instead of mb_detect_encoding. Defines: utf-8, windows-1251, koi8-r, iso-8859-5, ibm866, .....",
|
4 |
+
"type": "library",
|
5 |
+
"keywords": [
|
6 |
+
"mb_detect_encoding",
|
7 |
+
"encoding",
|
8 |
+
"utf-8",
|
9 |
+
"windows-1251",
|
10 |
+
"koi8-r",
|
11 |
+
"iso-8859-5",
|
12 |
+
"ibm866",
|
13 |
+
"cyrillic",
|
14 |
+
"iconv"
|
15 |
+
],
|
16 |
+
"homepage": "https://github.com/onnov/detect-encoding",
|
17 |
+
"license": "MIT",
|
18 |
+
"authors": [
|
19 |
+
{
|
20 |
+
"name": "onnov",
|
21 |
+
"email": "oblnn@yandex.ru"
|
22 |
+
}
|
23 |
+
],
|
24 |
+
"require": {
|
25 |
+
"php": ">=7.2",
|
26 |
+
"ext-iconv": "*"
|
27 |
+
},
|
28 |
+
"autoload": {
|
29 |
+
"psr-4": {
|
30 |
+
"Onnov\\DetectEncoding\\": "src/"
|
31 |
+
}
|
32 |
+
},
|
33 |
+
"autoload-dev": {
|
34 |
+
"psr-4": {
|
35 |
+
"Onnov\\DetectEncoding\\Tests\\": "tests/"
|
36 |
+
}
|
37 |
+
},
|
38 |
+
"require-dev": {
|
39 |
+
"phpunit/phpunit": "*",
|
40 |
+
"phpbench/phpbench": "*",
|
41 |
+
"phpmd/phpmd": "*",
|
42 |
+
"phpstan/phpstan": "*",
|
43 |
+
"phpstan/phpstan-strict-rules": "*",
|
44 |
+
"squizlabs/php_codesniffer": "*",
|
45 |
+
"infection/infection": "*",
|
46 |
+
"phpcompatibility/php-compatibility": "*",
|
47 |
+
"roave/backward-compatibility-check": "*"
|
48 |
+
},
|
49 |
+
"scripts": {
|
50 |
+
"phpcs": "phpcs",
|
51 |
+
"phpcbf": "phpcbf",
|
52 |
+
"phpmd": "phpmd src text cleancode,codesize,controversial,design,naming,unusedcode",
|
53 |
+
"phpstan": "phpstan analyse src/ -c phpstan.neon --level=7 --no-progress -vvv --memory-limit=-1",
|
54 |
+
"phpunit": "phpunit",
|
55 |
+
"infection": "infection --min-msi=50 --min-covered-msi=70 --log-verbosity=all",
|
56 |
+
"coveragehtml": "phpunit --coverage-text --coverage-html ./build/coverage/html --coverage-clover ./build/coverage/clover.xml",
|
57 |
+
"coverage": "phpunit --coverage-text --coverage-clover clover.xml",
|
58 |
+
"phpbench": "phpbench run benchmarks --report=default",
|
59 |
+
"bccheck": "roave-backward-compatibility-check"
|
60 |
+
}
|
61 |
+
}
|
vendor/onnov/detect-encoding/infection.json.dist
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"timeout": 5,
|
3 |
+
"source": {
|
4 |
+
"directories": [
|
5 |
+
"src"
|
6 |
+
]
|
7 |
+
},
|
8 |
+
"logs": {
|
9 |
+
"text": "build/infection/text.log",
|
10 |
+
"summary": "build/infection/summary.log",
|
11 |
+
"debug": "build/infection/debug.log",
|
12 |
+
"perMutator": "build/infection/perMutator.md"
|
13 |
+
},
|
14 |
+
"mutators": {
|
15 |
+
"@default": true
|
16 |
+
}
|
17 |
+
}
|
vendor/onnov/detect-encoding/phpbench.json
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"bootstrap": "vendor/autoload.php"
|
3 |
+
}
|
vendor/onnov/detect-encoding/src/CodePage.php
ADDED
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare(strict_types=1);
|
2 |
+
/**
|
3 |
+
* User: onnov
|
4 |
+
* Date: 02.09.2019
|
5 |
+
* Time: 18:25
|
6 |
+
*/
|
7 |
+
|
8 |
+
namespace Onnov\DetectEncoding;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Class CodePage
|
12 |
+
*
|
13 |
+
* @package Onnov\DetectEncoding
|
14 |
+
*/
|
15 |
+
class CodePage
|
16 |
+
{
|
17 |
+
/**
|
18 |
+
* Method to get a custom encoding range
|
19 |
+
*
|
20 |
+
* @param string $uppercaseLetters
|
21 |
+
* @param string $lowercaseLetters
|
22 |
+
* @param string $encoding
|
23 |
+
*
|
24 |
+
* @return array<string, array<string, string>>
|
25 |
+
*/
|
26 |
+
public function getRange(
|
27 |
+
string $uppercaseLetters,
|
28 |
+
string $lowercaseLetters,
|
29 |
+
string $encoding
|
30 |
+
): array {
|
31 |
+
return [
|
32 |
+
$encoding => [
|
33 |
+
'upper' => $this->getRangeStr($this->getLetterArr(
|
34 |
+
$uppercaseLetters,
|
35 |
+
$encoding
|
36 |
+
)),
|
37 |
+
'lower' => $this->getRangeStr($this->getLetterArr(
|
38 |
+
$lowercaseLetters,
|
39 |
+
$encoding
|
40 |
+
)),
|
41 |
+
],
|
42 |
+
];
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @param array $array
|
47 |
+
*
|
48 |
+
* @return string
|
49 |
+
*/
|
50 |
+
private function getRangeStr(array $array): string
|
51 |
+
{
|
52 |
+
$ranges = [];
|
53 |
+
$last = null;
|
54 |
+
foreach ($array as $current) {
|
55 |
+
if ($current > $last + 1) {
|
56 |
+
$lastKey = array_key_last($ranges);
|
57 |
+
if (null !== $lastKey) {
|
58 |
+
$ranges[$lastKey][1] = $last;
|
59 |
+
}
|
60 |
+
$ranges[] = [$current, null];
|
61 |
+
}
|
62 |
+
$last = $current;
|
63 |
+
}
|
64 |
+
$lastKey = array_key_last($ranges);
|
65 |
+
$ranges[$lastKey][1] = $last;
|
66 |
+
|
67 |
+
$stringIntervals = [];
|
68 |
+
foreach ($ranges as $interval) {
|
69 |
+
if (current($interval) < end($interval)) {
|
70 |
+
$stringIntervals[] = implode('-', $interval);
|
71 |
+
continue;
|
72 |
+
}
|
73 |
+
$stringIntervals[] = array_pop($interval);
|
74 |
+
}
|
75 |
+
$string = implode(', ', $stringIntervals);
|
76 |
+
|
77 |
+
return $string;
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* @param string $strLetters
|
82 |
+
* @param string $encoding
|
83 |
+
*
|
84 |
+
* @return array<int, int|string>
|
85 |
+
*/
|
86 |
+
private function getLetterArr(string &$strLetters, string $encoding): array
|
87 |
+
{
|
88 |
+
$res = [];
|
89 |
+
$str = iconv('utf-8', $encoding . '//IGNORE', $strLetters);
|
90 |
+
if (is_string($str)) {
|
91 |
+
$res = array_keys(count_chars($str, 1));
|
92 |
+
}
|
93 |
+
|
94 |
+
return $res;
|
95 |
+
}
|
96 |
+
}
|
vendor/onnov/detect-encoding/src/EncodingDetector.php
ADDED
@@ -0,0 +1,244 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare(strict_types=1);
|
2 |
+
/**
|
3 |
+
* User: onnov
|
4 |
+
* Date: 27.08.2019
|
5 |
+
* Time: 21:59
|
6 |
+
*/
|
7 |
+
|
8 |
+
namespace Onnov\DetectEncoding;
|
9 |
+
|
10 |
+
use Exception;
|
11 |
+
use RuntimeException;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Class EncodingDetector
|
15 |
+
*
|
16 |
+
* @package Onnov\DetectEncoding
|
17 |
+
*/
|
18 |
+
class EncodingDetector
|
19 |
+
{
|
20 |
+
const LOWER_FACTOR = 3;
|
21 |
+
|
22 |
+
const UTF_8 = 'utf-8';
|
23 |
+
const WINDOWS_1251 = 'windows-1251';
|
24 |
+
const KOI8_R = 'koi8-r';
|
25 |
+
const IBM866 = 'ibm866';
|
26 |
+
const ISO_8859_5 = 'iso-8859-5';
|
27 |
+
const MAC_CYRILLIC = 'mac-cyrillic';
|
28 |
+
|
29 |
+
/** @var array<string, array<string, string>> */
|
30 |
+
protected $rangeModel
|
31 |
+
= [
|
32 |
+
'windows-1251' => [
|
33 |
+
'upper' => '168,192-212,214-223',
|
34 |
+
'lower' => '184,224-255',
|
35 |
+
],
|
36 |
+
'koi8-r' => [
|
37 |
+
'upper' => '179,224-231, 233-255',
|
38 |
+
'lower' => '163,192-223',
|
39 |
+
],
|
40 |
+
'iso-8859-5' => [
|
41 |
+
'upper' => '161,176-196,198-207',
|
42 |
+
'lower' => '208-239,241',
|
43 |
+
],
|
44 |
+
'ibm866' => [
|
45 |
+
'upper' => '128-148,150-159,240',
|
46 |
+
'lower' => '160-175,224-239,241',
|
47 |
+
],
|
48 |
+
'mac-cyrillic' => [
|
49 |
+
'upper' => '128-148,150-159,221',
|
50 |
+
'lower' => '222-254',
|
51 |
+
],
|
52 |
+
];
|
53 |
+
|
54 |
+
/** @var array */
|
55 |
+
protected $ranges;
|
56 |
+
|
57 |
+
/**
|
58 |
+
* EncodingDetector constructor.
|
59 |
+
*/
|
60 |
+
public function __construct()
|
61 |
+
{
|
62 |
+
// default setting
|
63 |
+
$this->enableEncoding(
|
64 |
+
[
|
65 |
+
$this::WINDOWS_1251,
|
66 |
+
$this::KOI8_R,
|
67 |
+
$this::ISO_8859_5,
|
68 |
+
]
|
69 |
+
);
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Method to enable encoding definition
|
74 |
+
* Example:
|
75 |
+
* $detector->enableEncoding([
|
76 |
+
* $detector::IBM866,
|
77 |
+
* $detector::MAC_CYRILLIC,
|
78 |
+
* ]);
|
79 |
+
*
|
80 |
+
* @param array $encodingList
|
81 |
+
*/
|
82 |
+
public function enableEncoding(array $encodingList): void
|
83 |
+
{
|
84 |
+
foreach ($encodingList as $encoding) {
|
85 |
+
if (isset($this->rangeModel[$encoding])) {
|
86 |
+
$this->ranges[$encoding]
|
87 |
+
= $this->getRanges($this->rangeModel[$encoding]);
|
88 |
+
}
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Method to disable encoding definition
|
94 |
+
* Example:
|
95 |
+
* $detector->disableEncoding([
|
96 |
+
* $detector::ISO_8859_5,
|
97 |
+
* ]);
|
98 |
+
*
|
99 |
+
* @param array $encodingList
|
100 |
+
*/
|
101 |
+
public function disableEncoding(array $encodingList): void
|
102 |
+
{
|
103 |
+
foreach ($encodingList as $encoding) {
|
104 |
+
unset($this->ranges[$encoding]);
|
105 |
+
}
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Method for adding custom encoding
|
110 |
+
* Example:
|
111 |
+
* $detector->addEncoding([
|
112 |
+
* 'encodingName' => [
|
113 |
+
* 'upper' => '1-50,200-250,253', // uppercase character number range
|
114 |
+
* 'lower' => '55-100,120-180,199', // lowercase character number range
|
115 |
+
* ],
|
116 |
+
* ]);
|
117 |
+
*
|
118 |
+
* @param array $ranges
|
119 |
+
*/
|
120 |
+
public function addEncoding(array $ranges): void
|
121 |
+
{
|
122 |
+
foreach ($ranges as $encoding => $config) {
|
123 |
+
if (isset($config['upper'], $config['lower'])) {
|
124 |
+
$this->ranges[$encoding] = $this->getRanges($config);
|
125 |
+
}
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Method for converting text of an unknown encoding into a given encoding, by default in utf-8
|
131 |
+
* optional parameters:
|
132 |
+
* $extra = '//TRANSLIT' (default setting) , other options: '' or '//IGNORE'
|
133 |
+
* $encoding = 'utf-8' (default setting) , other options: any encoding that is available iconv
|
134 |
+
*
|
135 |
+
* @param string $text
|
136 |
+
* @param string $extra
|
137 |
+
* @param string $encoding
|
138 |
+
*
|
139 |
+
* @return string
|
140 |
+
* @throws RuntimeException
|
141 |
+
*/
|
142 |
+
public function iconvXtoEncoding(
|
143 |
+
string &$text,
|
144 |
+
string $extra = '//TRANSLIT',
|
145 |
+
string $encoding = EncodingDetector::UTF_8
|
146 |
+
): string {
|
147 |
+
$res = $text;
|
148 |
+
$xec = $this->getEncoding($text);
|
149 |
+
if ($xec !== $encoding) {
|
150 |
+
$msg = 'iconv returned false';
|
151 |
+
try {
|
152 |
+
$res = iconv($xec, $encoding . $extra, $text);
|
153 |
+
if ($res === false) {
|
154 |
+
throw new RuntimeException($msg);
|
155 |
+
}
|
156 |
+
} catch (Exception $error) {
|
157 |
+
$msg = $error->getMessage();
|
158 |
+
throw new RuntimeException($msg);
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
return $res;
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Definition of text encoding
|
167 |
+
*
|
168 |
+
* @param string $text
|
169 |
+
*
|
170 |
+
* @return string
|
171 |
+
*/
|
172 |
+
public function getEncoding(string &$text): string
|
173 |
+
{
|
174 |
+
$result = $this::UTF_8;
|
175 |
+
if ($this->isUtf($text) == false) {
|
176 |
+
$res = [];
|
177 |
+
$text = count_chars($text, 1);
|
178 |
+
foreach ($this->ranges as $encoding => $config) {
|
179 |
+
$upc = array_intersect_key($text, $config['upper']);
|
180 |
+
$loc = array_intersect_key($text, $config['lower']);
|
181 |
+
$res[$encoding] = (array_sum($upc) + array_sum($loc)
|
182 |
+
* EncodingDetector::LOWER_FACTOR);
|
183 |
+
}
|
184 |
+
asort($res);
|
185 |
+
$result = (string)array_key_last($res);
|
186 |
+
}
|
187 |
+
|
188 |
+
return $result;
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* UTF Encoding Definition Method
|
193 |
+
*
|
194 |
+
* @param string $text
|
195 |
+
*
|
196 |
+
* @return bool
|
197 |
+
*/
|
198 |
+
private function isUtf(string &$text): bool
|
199 |
+
{
|
200 |
+
return (bool)preg_match('/./u', $text);
|
201 |
+
}
|
202 |
+
|
203 |
+
/**
|
204 |
+
* @param array $config
|
205 |
+
*
|
206 |
+
* @return array
|
207 |
+
*/
|
208 |
+
private function getRanges(array $config): array
|
209 |
+
{
|
210 |
+
return [
|
211 |
+
'upper' => $this->getRange($config['upper']),
|
212 |
+
'lower' => $this->getRange($config['lower']),
|
213 |
+
];
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Method to convert a range from a string to an array
|
218 |
+
*
|
219 |
+
* @param string $str
|
220 |
+
*
|
221 |
+
* @return array|null
|
222 |
+
*/
|
223 |
+
private function getRange(string &$str): ?array
|
224 |
+
{
|
225 |
+
$res = [];
|
226 |
+
foreach (explode(',', $str) as $item) {
|
227 |
+
$arr = explode('-', $item);
|
228 |
+
if (count($arr) > 1) {
|
229 |
+
$arr = range($arr[0], $arr[1]);
|
230 |
+
}
|
231 |
+
$res = array_merge($res, $arr);
|
232 |
+
}
|
233 |
+
|
234 |
+
return array_flip($res);
|
235 |
+
}
|
236 |
+
|
237 |
+
/**
|
238 |
+
* @return array<string, array<string, string>>
|
239 |
+
*/
|
240 |
+
public function getEncodingList(): array
|
241 |
+
{
|
242 |
+
return $this->ranges;
|
243 |
+
}
|
244 |
+
}
|
vendor/rosell-dk/webp-convert/.github/FUNDING.yml
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
github: rosell-dk
|
2 |
+
ko_fi: rosell
|
vendor/rosell-dk/webp-convert/BACKERS.md
CHANGED
@@ -8,20 +8,25 @@ How is it financed then? Well, it isn't exactly. However, some people choose to
|
|
8 |
To become a backer yourself, visit [my page at patreon](https://www.patreon.com/rosell)
|
9 |
|
10 |
|
11 |
-
##
|
12 |
|
13 |
-
| Name
|
14 |
-
|
|
15 |
-
|
|
16 |
-
|
|
|
|
|
|
17 |
|
18 |
-
<sub>I reserve the right to disallow inappropriate messages. No Trump hooting or bashing here, please. And don't be aggressive, obscene or anything unpleasant. But I don't have to point that out, do I?</sub>
|
19 |
|
20 |
-
|
21 |
|
22 |
-
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
I reserve the right to disallow inappropriate messages and links. No xxx sites or anything freaky or fishy, please. You may however advertise non-freaky-or-fishy things, if you wish. Just remember the audience. No point in trying to sell shoes here</sub>
|
8 |
To become a backer yourself, visit [my page at patreon](https://www.patreon.com/rosell)
|
9 |
|
10 |
|
11 |
+
## Active backers via Patron
|
12 |
|
13 |
+
| Name | Since date |
|
14 |
+
| ---------------------- | -------------- |
|
15 |
+
| Max Kreminsky | 2019-08-02 |
|
16 |
+
| [Mathieu Gollain-Dupont](https://www.linkedin.com/in/mathieu-gollain-dupont-9938a4a/) | 2020-08-26 |
|
17 |
+
| Nodeflame | 2019-10-31 |
|
18 |
+
| Ruben Solvang | 2020-01-08 |
|
19 |
|
|
|
20 |
|
21 |
+
Hi-scores:
|
22 |
|
23 |
+
| Name | Life time contribution |
|
24 |
+
| ------------------------ | ------------------------ |
|
25 |
+
| Tammy Valgardson | $90 |
|
26 |
+
| Max Kreminsky | $65 |
|
27 |
+
| Ruben Solvang | $14 |
|
28 |
+
| Dmitry Verzjikovsky | $5 |
|
29 |
|
30 |
+
## Former backers - I'm still grateful :)
|
31 |
+
- Dmitry Verzjikovsky
|
32 |
+
- Tammy Valgardson
|
|
vendor/rosell-dk/webp-convert/README.md
CHANGED
@@ -18,6 +18,7 @@ The library can convert using the following methods:
|
|
18 |
- *gmagick* (using [Gmagick PHP extension](https://www.php.net/manual/en/book.gmagick.php))
|
19 |
- *imagemagick* (executing [imagemagick](https://imagemagick.org/index.php) binary using an `exec` call)
|
20 |
- *graphicsmagick* (executing [graphicsmagick](http://www.graphicsmagick.org/) binary using an `exec` call)
|
|
|
21 |
- *wpc* (using [WebPConvert Cloud Service](https://github.com/rosell-dk/webp-convert-cloud-service/) - an open source webp converter for PHP - based on this library)
|
22 |
- *ewwww* (using the [ewww](https://ewww.io/plans/) cloud converter (1 USD startup and then free webp conversion))
|
23 |
- *gd* (using the [Gd PHP extension](https://www.php.net/manual/en/book.image.php))
|
@@ -35,8 +36,6 @@ composer require rosell-dk/webp-convert
|
|
35 |
Here is a minimal example of converting using the *WebPConvert::convert* method:
|
36 |
|
37 |
```php
|
38 |
-
<?php
|
39 |
-
|
40 |
// Initialise your autoloader (this example is using Composer)
|
41 |
require 'vendor/autoload.php';
|
42 |
|
@@ -58,7 +57,6 @@ The *WebPConvert::serveConverted* method tries to serve a converted image. If th
|
|
58 |
|
59 |
Example (version 2.0):
|
60 |
```php
|
61 |
-
<?php
|
62 |
require 'vendor/autoload.php';
|
63 |
use WebPConvert\WebPConvert;
|
64 |
|
@@ -115,4 +113,27 @@ The webp-convert library and its dependents as a single PHP file (or two)
|
|
115 |
## Supporting WebP Convert
|
116 |
Bread on the table don't come for free, even though this library does, and always will. I enjoy developing this, and supporting you guys, but I kind of need the bread too. Please make it possible for me to have both:
|
117 |
|
118 |
-
[Become a backer or sponsor on Patreon](https://www.patreon.com/rosell).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
- *gmagick* (using [Gmagick PHP extension](https://www.php.net/manual/en/book.gmagick.php))
|
19 |
- *imagemagick* (executing [imagemagick](https://imagemagick.org/index.php) binary using an `exec` call)
|
20 |
- *graphicsmagick* (executing [graphicsmagick](http://www.graphicsmagick.org/) binary using an `exec` call)
|
21 |
+
- **NEW in 2.4.0:** *ffmpeg* (executing [ffmpeg](https://ffmpeg.org/) binary using an `exec` call)
|
22 |
- *wpc* (using [WebPConvert Cloud Service](https://github.com/rosell-dk/webp-convert-cloud-service/) - an open source webp converter for PHP - based on this library)
|
23 |
- *ewwww* (using the [ewww](https://ewww.io/plans/) cloud converter (1 USD startup and then free webp conversion))
|
24 |
- *gd* (using the [Gd PHP extension](https://www.php.net/manual/en/book.image.php))
|
36 |
Here is a minimal example of converting using the *WebPConvert::convert* method:
|
37 |
|
38 |
```php
|
|
|
|
|
39 |
// Initialise your autoloader (this example is using Composer)
|
40 |
require 'vendor/autoload.php';
|
41 |
|
57 |
|
58 |
Example (version 2.0):
|
59 |
```php
|
|
|
60 |
require 'vendor/autoload.php';
|
61 |
use WebPConvert\WebPConvert;
|
62 |
|
113 |
## Supporting WebP Convert
|
114 |
Bread on the table don't come for free, even though this library does, and always will. I enjoy developing this, and supporting you guys, but I kind of need the bread too. Please make it possible for me to have both:
|
115 |
|
116 |
+
- [Become a backer or sponsor on Patreon](https://www.patreon.com/rosell).
|
117 |
+
- [Buy me a Coffee](https://ko-fi.com/rosell)
|
118 |
+
|
119 |
+
## Supporters ==
|
120 |
+
*Persons currently backing the project via patreon - Thanks!*
|
121 |
+
|
122 |
+
- Max Kreminsky
|
123 |
+
- Nodeflame
|
124 |
+
- [Mathieu Gollain-Dupont](https://www.linkedin.com/in/mathieu-gollain-dupont-9938a4a/)
|
125 |
+
- Ruben Solvang
|
126 |
+
|
127 |
+
*Persons who contributed with coffee within the last 30 days:*
|
128 |
+
|
129 |
+
- Anon
|
130 |
+
- Eder Ribeiro
|
131 |
+
- Christian
|
132 |
+
|
133 |
+
*Persons who contributed with extra generously amounts of coffee / lifetime backing (>50$) - thanks!:*
|
134 |
+
|
135 |
+
- Justin - BigScoots ($105)
|
136 |
+
- Sebastian ($99)
|
137 |
+
- Tammy Lee ($90)
|
138 |
+
- Max Kreminsky ($65)
|
139 |
+
- Steven Sullivan ($51)
|
vendor/rosell-dk/webp-convert/docs/development.md
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Development
|
2 |
+
|
3 |
+
## Setting up the environment.
|
4 |
+
|
5 |
+
First, clone the repository:
|
6 |
+
```
|
7 |
+
cd whatever/folder/you/want
|
8 |
+
git clone https://github.com/rosell-dk/webp-convert.git
|
9 |
+
```
|
10 |
+
|
11 |
+
Then install the dev tools with composer:
|
12 |
+
|
13 |
+
```
|
14 |
+
composer install
|
15 |
+
```
|
16 |
+
|
17 |
+
## Unit Testing
|
18 |
+
To run all the unit tests do this:
|
19 |
+
```
|
20 |
+
composer test
|
21 |
+
```
|
22 |
+
This also runs tests on the builds.
|
23 |
+
|
24 |
+
|
25 |
+
Individual test files can be executed like this:
|
26 |
+
```
|
27 |
+
composer phpunit tests/Convert/Converters/WPCTest
|
28 |
+
composer phpunit tests/Serve/ServeConvertedTest
|
29 |
+
```
|
30 |
+
|
31 |
+
|
32 |
+
## Coding styles
|
33 |
+
WebPConvert complies with the [PSR-2](https://www.php-fig.org/psr/psr-2/) coding standard.
|
34 |
+
|
35 |
+
To validate coding style of all files, do this:
|
36 |
+
```
|
37 |
+
composer phpcs src
|
38 |
+
```
|
39 |
+
|
40 |
+
To automatically fix the coding style of all files, using [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer), do this:
|
41 |
+
```
|
42 |
+
composer phpcbf src
|
43 |
+
```
|
44 |
+
|
45 |
+
Or, alternatively, you can fix with the use the [PHP-CS-FIXER](https://github.com/FriendsOfPHP/PHP-CS-Fixer) library instead:
|
46 |
+
```
|
47 |
+
composer cs-fix
|
48 |
+
```
|
49 |
+
|
50 |
+
## Running all tests in one command
|
51 |
+
The following script runs the unit tests, checks the coding styles, validates `composer.json` and runs the builds.
|
52 |
+
Run this before pushing anything to github. "ci" btw stands for *continuous integration*.
|
53 |
+
```
|
54 |
+
composer ci
|
55 |
+
```
|
56 |
+
|
57 |
+
## Generating api docs
|
58 |
+
Install phpdox and run it in the project root:
|
59 |
+
```
|
60 |
+
phpdox
|
61 |
+
```
|
62 |
+
|
63 |
+
## Committing
|
64 |
+
Before committing, first make sure to:
|
65 |
+
- run `composer ci`
|
66 |
+
|
67 |
+
## Releasing
|
68 |
+
Before releasing:
|
69 |
+
- Update the version number in `Converters/AbstractConverter.php` (search for "WebP Convert")
|
70 |
+
- Make sure that travis build is successful
|
71 |
+
|
72 |
+
When releasing:
|
73 |
+
- update the [webp-convert-concat](https://github.com/rosell-dk/webp-convert-concat) library
|
74 |
+
- consider updating the require in the composer file in libraries that uses webp-convert (ie `webp-convert-cloud-service` and `webp-express`)
|
vendor/rosell-dk/webp-convert/docs/v1.3/converting/convert-options.md
ADDED
@@ -0,0 +1,322 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# The webp converters
|
2 |
+
|
3 |
+
## The converters at a glance
|
4 |
+
When it comes to webp conversion, there is actually only one library in town: *libwebp* from Google. All conversion methods below ultimately uses that very same library for conversion. This means that it does not matter much, which conversion method you use. Whatever works. There is however one thing to take note of, if you set *quality* to *auto*, and your system cannot determine the quality of the source (this requires imagick or gmagick), and you do not have access to install those, then the only way to get quality-detection is to connect to a *wpc* cloud converter. However, with *cwebp*, you can specify the desired reduction (the *size-in-percentage* option) - at the cost of doubling the conversion time. Read more about those considerations in the API.
|
5 |
+
|
6 |
+
Speed-wise, there is too little difference for it to matter, considering that images usually needs to be converted just once. Anyway, here are the results: *cweb* is the fastest (with method=3). *gd* is right behind, merely 3% slower than *cwebp*. *gmagick* are third place, ~8% slower than *cwebp*. *imagick* comes in ~22% slower than *cwebp*. *ewww* depends on connection speed. On my *digital ocean* account, it takes ~2 seconds to upload, convert, and download a tiny image (10 times longer than the local *cwebp*). A 1MB image however only takes ~4.5 seconds to upload, convert and download (1.5 seconds longer). A 2 MB image takes ~5 seconds to convert (only 16% longer than my *cwebp*). The *ewww* thus converts at a very decent speeds. Probably faster than your average shared host. If multiple big images needs to be converted at the same time, *ewww* will probably perform much better than the local converters.
|
7 |
+
|
8 |
+
[`cwebp`](#cwebp) works by executing the *cwebp* binary from Google, which is build upon the *libwebp* (also from Google). That library is actually the only library in town for generating webp images, which means that the other conversion methods ultimately uses that very same library. Which again means that the results using the different methods are very similar. However, with *cwebp*, we have more parameters to tweak than with the rest. We for example have the *method* option, which controls the trade off between encoding speed and the compressed file size and quality. Setting this to max, we can squeeze the images a few percent extra - without loosing quality (the converter is still pretty fast, so in most cases it is probably worth it).
|
9 |
+
|
10 |
+
Of course, as we here have to call a binary directly, *cwebp* requires the *exec* function to be enabled, and that the webserver user is allowed to execute the `cwebp` binary (either at known system locations, or one of the precompiled binaries, that comes with this library).
|
11 |
+
|
12 |
+
[`vips`](#vips) (**new in 2.0**) works by using the vips extension, if available. Vips is great! It offers many webp options, it is fast and installation is easier than imagick and gd, as it does not need to be configured for webp support.
|
13 |
+
|
14 |
+
[`imagick`](#imagick) does not support any special webp options, but is at least able to strip all metadata, if metadata is set to none. Imagick has a very nice feature - that it is able to detect the quality of a jpeg file. This enables it to automatically use same quality for destination as for source, which eliminates the risk of setting quality higher for the destination than for source (the result of that is that the file size gets higher, but the quality remains the same). As the other converters lends this capability from Imagick, this is however no reason for using Imagick rather than the other converters. Requirements: Imagick PHP extension compiled with WebP support
|
15 |
+
|
16 |
+
[`gmagick`](#gmagick) uses the *gmagick* extension. It is very similar to *imagick*. Requirements: Gmagick PHP extension compiled with WebP support.
|
17 |
+
|
18 |
+
[`gd`](#gd) uses the *Gd* extension to do the conversion. The *Gd* extension is pretty common, so the main feature of this converter is that it may work out of the box. It does not support any webp options, and does not support stripping metadata. Requirements: GD PHP extension compiled with WebP support.
|
19 |
+
|
20 |
+
[`wpc`](#wpc) is an open source cloud service for converting images to webp. To use it, you must either install [webp-convert-cloud-service](https://github.com/rosell-dk/webp-convert-cloud-service) directly on a remote server, or install the Wordpress plugin, [WebP Express](https://github.com/rosell-dk/webp-express) in Wordpress. Btw: Beware that upload limits will prevent conversion of big images. The converter checks your *php.ini* settings and abandons upload right away, if an image is larger than your *upload_max_filesize* or your *post_max_size* setting. Requirements: Access to a running service. The service can be installed [directly](https://github.com/rosell-dk/webp-convert-cloud-service) or by using [this Wordpress plugin](https://wordpress.org/plugins/webp-express/)
|
21 |
+
|
22 |
+
[`ewww`](#ewww) is also a cloud service. Not free, but cheap enough to be considered *practically* free. It supports lossless encoding, but this cannot be controlled. *Ewww* always uses lossy encoding for jpeg and lossless for png. For jpegs this is usually a good choice, however, many pngs are compressed better using lossy encoding. As lossless cannot be controlled, the "lossless:auto" option cannot be used for automatically trying both lossy and lossless and picking the smallest file. Also, unfortunately, *ewww* does not support quality=auto, like *wpc*, and it does not support *size-in-percentage* like *cwebp*, either. I have requested such features, and he is considering... As with *wpc*, beware of upload limits. Requirements: A key to the *EWWW Image Optimizer* cloud service. Can be purchaced [here](https://ewww.io/plans/)
|
23 |
+
|
24 |
+
[`stack`](#stack) takes a stack of converters and tries it from the top, until success. The main convert method actually calls this converter. Stacks within stacks are supported (not really needed, though).
|
25 |
+
|
26 |
+
|
27 |
+
**Summary:**
|
28 |
+
|
29 |
+
| | cwebp | vips | imagick / gmagick | imagickbinary | gd | ewww |
|
30 |
+
| ------------------------------------------ | --------- | ------ | ----------------- | ------------- | --------- | ------ |
|
31 |
+
| supports lossless encoding ? | yes | yes | no | no | no | yes |
|
32 |
+
| supports lossless auto ? | yes | yes | no | no | no | no |
|
33 |
+
| supports near-lossless ? | yes | yes | no | no | no | ? |
|
34 |
+
| supports metadata stripping / preserving | yes | yes | yes | no | no | ? |
|
35 |
+
| supports setting alpha quality | no | yes | no | no | no | no |
|
36 |
+
| supports fixed quality (for lossy) | yes | yes | yes | yes | yes | yes |
|
37 |
+
| supports auto quality without help | no | no | yes | yes | no | no |
|
38 |
+
|
39 |
+
|
40 |
+
|
41 |
+
*WebPConvert* currently supports the following converters:
|
42 |
+
|
43 |
+
| Converter | Method | Requirements |
|
44 |
+
| ------------------------------------ | ------------------------------------------------ | -------------------------------------------------- |
|
45 |
+
| [`cwebp`](#cwebp) | Calls `cwebp` binary directly | `exec()` function *and* that the webserver user has permission to run `cwebp` binary |
|
46 |
+
| [`vips`](#vips) (new in 2.0) | Vips extension | Vips extension |
|
47 |
+
| [`imagick`](#imagick) | Imagick extension (`ImageMagick` wrapper) | Imagick PHP extension compiled with WebP support |
|
48 |
+
| [`gmagick`](#gmagick) | Gmagick extension (`ImageMagick` wrapper) | Gmagick PHP extension compiled with WebP support |
|
49 |
+
| [`gd`](#gd) | GD Graphics (Draw) extension (`LibGD` wrapper) | GD PHP extension compiled with WebP support |
|
50 |
+
| [`imagickbinary`](#imagickbinary) | Calls imagick binary directly | exec() and imagick installed and compiled with WebP support |
|
51 |
+
| [`wpc`](#wpc) | Connects to an open source cloud service | Access to a running service. The service can be installed [directly](https://github.com/rosell-dk/webp-convert-cloud-service) or by using [this Wordpress plugin](https://wordpress.org/plugins/webp-express/).
|
52 |
+
| [`ewww`](#ewww) | Connects to *EWWW Image Optimizer* cloud service | Purchasing a key |
|
53 |
+
|
54 |
+
## Installation
|
55 |
+
Instructions regarding getting the individual converters to work are [on the wiki](https://github.com/rosell-dk/webp-convert/wiki)
|
56 |
+
|
57 |
+
## cwebp
|
58 |
+
<table>
|
59 |
+
<tr><th>Requirements</th><td><code>exec()</code> function and that the webserver has permission to run `cwebp` binary (either found in system path, or a precompiled version supplied with this library)</td></tr>
|
60 |
+
<tr><th>Performance</th><td>~40-120ms to convert a 40kb image (depending on *method* option)</td></tr>
|
61 |
+
<tr><th>Reliability</th><td>No problems detected so far!</td></tr>
|
62 |
+
<tr><th>Availability</th><td>According to ewww docs, requirements are met on surprisingly many webhosts. Look <a href="https://docs.ewww.io/article/43-supported-web-hosts">here</a> for a list</td></tr>
|
63 |
+
<tr><th>General options supported</th><td>All (`quality`, `metadata`, `lossless`)</td></tr>
|
64 |
+
<tr><th>Extra options</th><td>`method` (0-6)<br>`use-nice` (boolean)<br>`try-common-system-paths` (boolean)<br> `try-supplied-binary-for-os` (boolean)<br>`autofilter` (boolean)<br>`size-in-percentage` (number / null)<br>`command-line-options` (string)<br>`low-memory` (boolean)</td></tr>
|
65 |
+
</table>
|
66 |
+
|
67 |
+
[cwebp](https://developers.google.com/speed/webp/docs/cwebp) is a WebP conversion command line converter released by Google. Our implementation ships with precompiled binaries for Linux, FreeBSD, WinNT, Darwin and SunOS. If however a cwebp binary is found in a usual location, that binary will be preferred. It is executed with [exec()](http://php.net/manual/en/function.exec.php).
|
68 |
+
|
69 |
+
In more detail, the implementation does this:
|
70 |
+
- It is tested whether cwebp is available in a common system path (eg `/usr/bin/cwebp`, ..)
|
71 |
+
- If not, then supplied binary is selected from `Converters/Binaries` (according to OS) - after validating checksum
|
72 |
+
- Command-line options are generated from the options
|
73 |
+
- If [`nice`]( https://en.wikipedia.org/wiki/Nice_(Unix)) command is found on host, binary is executed with low priority in order to save system resources
|
74 |
+
- Permissions of the generated file are set to be the same as parent folder
|
75 |
+
|
76 |
+
### Cwebp options
|
77 |
+
|
78 |
+
The following options are supported, besides the general options (such as quality, lossless etc):
|
79 |
+
|
80 |
+
| Option | Type | Default |
|
81 |
+
| -------------------------- | ------------------------- | -------------------------- |
|
82 |
+
| autofilter | boolean | false |
|
83 |
+
| command-line-options | string | '' |
|
84 |
+
| low-memory | boolean | false |
|
85 |
+
| method | integer (0-6) | 6 |
|
86 |
+
| near-lossless | integer (0-100) | 60 |
|
87 |
+
| size-in-percentage | integer (0-100) (or null) | null |
|
88 |
+
| rel-path-to-precompiled-binaries | string | './Binaries' |
|
89 |
+
| size-in-percentage | number (or null) | is_null |
|
90 |
+
| try-common-system-paths | boolean | true |
|
91 |
+
| try-supplied-binary-for-os | boolean | true |
|
92 |
+
| use-nice | boolean | false |
|
93 |
+
|
94 |
+
Descriptions (only of some of the options):
|
95 |
+
|
96 |
+
#### the `autofilter` option
|
97 |
+
Turns auto-filter on. This algorithm will spend additional time optimizing the filtering strength to reach a well-balanced quality. Unfortunately, it is extremely expensive in terms of computation. It takes about 5-10 times longer to do a conversion. A 1MB picture which perhaps typically takes about 2 seconds to convert, will takes about 15 seconds to convert with auto-filter. So in most cases, you will want to leave this at its default, which is off.
|
98 |
+
|
99 |
+
#### the `command-line-options` option
|
100 |
+
This allows you to set any parameter available for cwebp in the same way as you would do when executing *cwebp*. You could ie set it to "-sharpness 5 -mt -crop 10 10 40 40". Read more about all the available parameters in [the docs](https://developers.google.com/speed/webp/docs/cwebp)
|
101 |
+
|
102 |
+
#### the `low-memory` option
|
103 |
+
Reduce memory usage of lossy encoding at the cost of ~30% longer encoding time and marginally larger output size. Default: `false`. Read more in [the docs](https://developers.google.com/speed/webp/docs/cwebp). Default: *false*
|
104 |
+
|
105 |
+
#### The `method` option
|
106 |
+
This parameter controls the trade off between encoding speed and the compressed file size and quality. Possible values range from 0 to 6. 0 is fastest. 6 results in best quality.
|
107 |
+
|
108 |
+
#### the `near-lossless` option
|
109 |
+
Specify the level of near-lossless image preprocessing. This option adjusts pixel values to help compressibility, but has minimal impact on the visual quality. It triggers lossless compression mode automatically. The range is 0 (maximum preprocessing) to 100 (no preprocessing). The typical value is around 60. Read more [here](https://groups.google.com/a/webmproject.org/forum/#!topic/webp-discuss/0GmxDmlexek). Default: 60
|
110 |
+
|
111 |
+
#### The `size-in-percentage` option
|
112 |
+
This option sets the file size, *cwebp* should aim for, in percentage of the original. If you for example set it to *45*, and the source file is 100 kb, *cwebp* will try to create a file with size 45 kb (we use the `-size` option). This is an excellent alternative to the "quality:auto" option. If the quality detection isn't working on your system (and you do not have the rights to install imagick or gmagick), you should consider using this options instead. *Cwebp* is generally able to create webp files with the same quality at about 45% the size. So *45* would be a good choice. The option overrides the quality option. And note that it slows down the conversion - it takes about 2.5 times longer to do a conversion this way, than when quality is specified. Default is *off* (null)
|
113 |
+
|
114 |
+
|
115 |
+
#### final words on cwebp
|
116 |
+
The implementation is based on the work of Shane Bishop for his plugin, [EWWW Image Optimizer](https://ewww.io). Thanks for letting us do that!
|
117 |
+
|
118 |
+
See [the wiki](https://github.com/rosell-dk/webp-convert/wiki/Installing-cwebp---using-official-precompilations) for instructions regarding installing cwebp or using official precompilations.
|
119 |
+
|
120 |
+
## vips
|
121 |
+
<table>
|
122 |
+
<tr><th>Requirements</th><td>Vips extension</td></tr>
|
123 |
+
<tr><th>Performance</th><td>Great</td></tr>
|
124 |
+
<tr><th>Reliability</th><td>No problems detected so far!</td></tr>
|
125 |
+
<tr><th>Availability</th><td>Not that widespread yet, but gaining popularity</td></tr>
|
126 |
+
<tr><th>General options supported</th><td>All (`quality`, `metadata`, `lossless`)</td></tr>
|
127 |
+
<tr><th>Extra options</th><td>`smart-subsample`(boolean)<br>`alpha-quality`(0-100)<br>`near-lossless` (0-100)<br> `preset` (0-6)</td></tr>
|
128 |
+
</table>
|
129 |
+
|
130 |
+
For installation instructions, go [here](https://github.com/libvips/php-vips-ext).
|
131 |
+
|
132 |
+
The options are described [here](https://jcupitt.github.io/libvips/API/current/VipsForeignSave.html#vips-webpsave)
|
133 |
+
|
134 |
+
*near-lossless* is however an integer (0-100), in order to have the option behave like in cwebp.
|
135 |
+
|
136 |
+
|
137 |
+
|
138 |
+
## wpc
|
139 |
+
*WebPConvert Cloud Service*
|
140 |
+
|
141 |
+
<table>
|
142 |
+
<tr><th>Requirements</th><td>Access to a server with [webp-convert-cloud-service](https://github.com/rosell-dk/webp-convert-cloud-service) installed, <code>cURL</code> and PHP >= 5.5.0</td></tr>
|
143 |
+
<tr><th>Performance</th><td>Depends on the server where [webp-convert-cloud-service](https://github.com/rosell-dk/webp-convert-cloud-service) is set up, and the speed of internet connections. But perhaps ~1000ms to convert a 40kb image</td></tr>
|
144 |
+
<tr><th>Reliability</th><td>Great (depends on the reliability on the server where it is set up)</td></tr>
|
145 |
+
<tr><th>Availability</th><td>Should work on <em>almost</em> any webhost</td></tr>
|
146 |
+
<tr><th>General options supported</th><td>All (`quality`, `metadata`, `lossless`)</td></tr>
|
147 |
+
<tr><th>Extra options (old api)</th><td>`url`, `secret`</td></tr>
|
148 |
+
<tr><th>Extra options (new api)</th><td>`url`, `api-version`, `api-key`, `crypt-api-key-in-transfer`</td></tr>
|
149 |
+
</table>
|
150 |
+
|
151 |
+
[wpc](https://github.com/rosell-dk/webp-convert-cloud-service) is an open source cloud service. You do not buy a key, you set it up on a server, or you set up [the Wordpress plugin](https://wordpress.org/plugins/webp-express/). As WebPConvert Cloud Service itself is based on WebPConvert, all options are supported.
|
152 |
+
|
153 |
+
To use it, you need to set the `converter-options` (to add url etc).
|
154 |
+
|
155 |
+
#### Example, where api-key is not crypted, on new API:
|
156 |
+
|
157 |
+
```php
|
158 |
+
WebPConvert::convert($source, $destination, [
|
159 |
+
'max-quality' => 80,
|
160 |
+
'converters' => ['cwebp', 'wpc'],
|
161 |
+
'converter-options' => [
|
162 |
+
'wpc' => [
|
163 |
+
'api-version' => 1, /* from wpc release 1.0.0 */
|
164 |
+
'url' => 'http://example.com/wpc.php',
|
165 |
+
'api-key' => 'my dog is white',
|
166 |
+
'crypt-api-key-in-transfer' => false
|
167 |
+
]
|
168 |
+
]
|
169 |
+
));
|
170 |
+
```
|
171 |
+
|
172 |
+
#### Example, where api-key is crypted:
|
173 |
+
|
174 |
+
```php
|
175 |
+
|
176 |
+
WebPConvert::convert($source, $destination, [
|
177 |
+
'max-quality' => 80,
|
178 |
+
'converters' => ['cwebp', 'wpc'],
|
179 |
+
'converter-options' => [
|
180 |
+
'wpc' => [
|
181 |
+
'api-version' => 1,
|
182 |
+
'url' => 'https://example.com/wpc.php',
|
183 |
+
'api-key' => 'my dog is white',
|
184 |
+
'crypt-api-key-in-transfer' => true
|
185 |
+
],
|
186 |
+
]
|
187 |
+
));
|
188 |
+
```
|
189 |
+
|
190 |
+
In 2.0, you can alternatively set the api key and urls through through the *WPC_API_KEY* and *WPC_API_URL* environment variables. This is a safer place to store it.
|
191 |
+
|
192 |
+
To set an environment variable in Apache, you can use the `SetEnv` directory. Ie, place something like the following in your virtual host / or .htaccess file (replace the key with the one you purchased!)
|
193 |
+
|
194 |
+
```
|
195 |
+
SetEnv WPC_API_KEY my-dog-is-dashed
|
196 |
+
SetEnv WPC_API_URL https://wpc.example.com/wpc.php
|
197 |
+
```
|
198 |
+
|
199 |
+
|
200 |
+
#### Example, old API:
|
201 |
+
|
202 |
+
```php
|
203 |
+
WebPConvert::convert($source, $destination, [
|
204 |
+
'max-quality' => 80,
|
205 |
+
'converters' => ['cwebp', 'wpc'],
|
206 |
+
'converter-options' => [
|
207 |
+
'wpc' => [
|
208 |
+
'url' => 'https://example.com/wpc.php',
|
209 |
+
'secret' => 'my dog is white',
|
210 |
+
],
|
211 |
+
]
|
212 |
+
));
|
213 |
+
```
|
214 |
+
|
215 |
+
|
216 |
+
## ewww
|
217 |
+
|
218 |
+
<table>
|
219 |
+
<tr><th>Requirements</th><td>Valid EWWW Image Optimizer <a href="https://ewww.io/plans/">API key</a>, <code>cURL</code> and PHP >= 5.5.0</td></tr>
|
220 |
+
<tr><th>Performance</th><td>~1300ms to convert a 40kb image</td></tr>
|
221 |
+
<tr><th>Reliability</th><td>Great (but, as with any cloud service, there is a risk of downtime)</td></tr>
|
222 |
+
<tr><th>Availability</th><td>Should work on <em>almost</em> any webhost</td></tr>
|
223 |
+
<tr><th>General options supported</th><td>`quality`, `metadata` (partly)</td></tr>
|
224 |
+
<tr><th>Extra options</th><td>`key`</td></tr>
|
225 |
+
</table>
|
226 |
+
|
227 |
+
EWWW Image Optimizer is a very cheap cloud service for optimizing images. After purchasing an API key, add the converter in the `extra-converters` option, with `key` set to the key. Be aware that the `key` should be stored safely to avoid exploitation - preferably in the environment, ie with [dotenv](https://github.com/vlucas/phpdotenv).
|
228 |
+
|
229 |
+
The EWWW api doesn't support the `lossless` option, but it does automatically convert PNG's losslessly. Metadata is either all or none. If you have set it to something else than one of these, all metadata will be preserved.
|
230 |
+
|
231 |
+
In more detail, the implementation does this:
|
232 |
+
- Validates that there is a key, and that `curl` extension is working
|
233 |
+
- Validates the key, using the [/verify/ endpoint](https://ewww.io/api/) (in order to [protect the EWWW service from unnecessary file uploads, when key has expired](https://github.com/rosell-dk/webp-convert/issues/38))
|
234 |
+
- Converts, using the [/ endpoint](https://ewww.io/api/).
|
235 |
+
|
236 |
+
<details>
|
237 |
+
<summary><strong>Roadmap</strong> 👁</summary>
|
238 |
+
|
239 |
+
The converter could be improved by using `fsockopen` when `cURL` is not available - which is extremely rare. PHP >= 5.5.0 is also widely available (PHP 5.4.0 reached end of life [more than two years ago!](http://php.net/supported-versions.php)).
|
240 |
+
</details>
|
241 |
+
|
242 |
+
#### Example:
|
243 |
+
|
244 |
+
```php
|
245 |
+
WebPConvert::convert($source, $destination, [
|
246 |
+
'max-quality' => 80,
|
247 |
+
'converters' => ['gd', 'ewww'],
|
248 |
+
'converter-options' => [
|
249 |
+
'ewww' => [
|
250 |
+
'key' => 'your-api-key-here'
|
251 |
+
],
|
252 |
+
]
|
253 |
+
));
|
254 |
+
```
|
255 |
+
In 2.0, you can alternatively set the api key by through the *EWWW_API_KEY* environment variable. This is a safer place to store it.
|
256 |
+
|
257 |
+
To set an environment variable in Apache, you can use the `SetEnv` directory. Ie, place something like the following in your virtual host / or .htaccess file (replace the key with the one you purchased!)
|
258 |
+
|
259 |
+
```
|
260 |
+
SetEnv EWWW_API_KEY sP3LyPpsKWZy8CVBTYegzEGN6VsKKKKA
|
261 |
+
```
|
262 |
+
|
263 |
+
## gd
|
264 |
+
|
265 |
+
<table>
|
266 |
+
<tr><th>Requirements</th><td>GD PHP extension and PHP >= 5.5.0 (compiled with WebP support)</td></tr>
|
267 |
+
<tr><th>Performance</th><td>~30ms to convert a 40kb image</td></tr>
|
268 |
+
<tr><th>Reliability</th><td>Not sure - I have experienced corrupted images, but cannot reproduce</td></tr>
|
269 |
+
<tr><th>Availability</th><td>Unfortunately, according to <a href="https://stackoverflow.com/questions/25248382/how-to-create-a-webp-image-in-php">this link</a>, WebP support on shared hosts is rare.</td></tr>
|
270 |
+
<tr><th>General options supported</th><td>`quality`</td></tr>
|
271 |
+
<tr><th>Extra options</th><td>`skip-pngs`</td></tr>
|
272 |
+
</table>
|
273 |
+
|
274 |
+
[imagewebp](http://php.net/manual/en/function.imagewebp.php) is a function that comes with PHP (>5.5.0), *provided* that PHP has been compiled with WebP support.
|
275 |
+
|
276 |
+
`gd` neither supports copying metadata nor exposes any WebP options. Lacking the option to set lossless encoding results in poor encoding of PNGs - the filesize is generally much larger than the original. For this reason, PNG conversion is *disabled* by default, but it can be enabled my setting `skip-pngs` option to `false`.
|
277 |
+
|
278 |
+
Installaition instructions are [available in the wiki](https://github.com/rosell-dk/webp-convert/wiki/Installing-Gd-extension).
|
279 |
+
|
280 |
+
<details>
|
281 |
+
<summary><strong>Known bugs</strong> 👁</summary>
|
282 |
+
Due to a [bug](https://bugs.php.net/bug.php?id=66590), some versions sometimes created corrupted images. That bug can however easily be fixed in PHP (fix was released [here](https://stackoverflow.com/questions/30078090/imagewebp-php-creates-corrupted-webp-files)). However, I have experienced corrupted images *anyway* (but cannot reproduce that bug). So use this converter with caution. The corrupted images look completely transparent in Google Chrome, but have the correct size.
|
283 |
+
</details>
|
284 |
+
|
285 |
+
## imagick
|
286 |
+
|
287 |
+
<table>
|
288 |
+
<tr><th>Requirements</th><td>Imagick PHP extension (compiled with WebP support)</td></tr>
|
289 |
+
<tr><th>Quality</th><td>Poor. [See this issue]( https://github.com/rosell-dk/webp-convert/issues/43)</td></tr>
|
290 |
+
<tr><th>General options supported</th><td>`quality`</td></tr>
|
291 |
+
<tr><th>Extra options</th><td>None</td></tr>
|
292 |
+
<tr><th>Performance</th><td>~20-320ms to convert a 40kb image</td></tr>
|
293 |
+
<tr><th>Reliability</th><td>No problems detected so far</td></tr>
|
294 |
+
<tr><th>Availability</th><td>Probably only available on few shared hosts (if any)</td></tr>
|
295 |
+
</table>
|
296 |
+
|
297 |
+
WebP conversion with `imagick` is fast and [exposes many WebP options](http://www.imagemagick.org/script/webp.php). Unfortunately, WebP support for the `imagick` extension is pretty uncommon. At least not on the systems I have tried (Ubuntu 16.04 and Ubuntu 17.04). But if installed, it works great and has several WebP options.
|
298 |
+
|
299 |
+
See [this page](https://github.com/rosell-dk/webp-convert/wiki/Installing-Imagick-extension) in the Wiki for instructions on installing the extension.
|
300 |
+
|
301 |
+
## imagickbinary
|
302 |
+
<table>
|
303 |
+
<tr><th>Requirements</th><td><code>exec()</code> function and that imagick is installed on webserver, compiled with webp support</td></tr>
|
304 |
+
<tr><th>Performance</th><td>just fine</td></tr>
|
305 |
+
<tr><th>Reliability</th><td>No problems detected so far!</td></tr>
|
306 |
+
<tr><th>Availability</th><td>Not sure</td></tr>
|
307 |
+
<tr><th>General options supported</th><td>`quality`</td></tr>
|
308 |
+
<tr><th>Extra options</th><td>`use-nice` (boolean)</td></tr>
|
309 |
+
</table>
|
310 |
+
|
311 |
+
This converter tryes to execute `convert source.jpg webp:destination.jpg.webp`.
|
312 |
+
|
313 |
+
## stack
|
314 |
+
|
315 |
+
<table>
|
316 |
+
<tr><th>General options supported</th><td>all (passed to the converters in the stack )</td></tr>
|
317 |
+
<tr><th>Extra options</th><td>`converters` (array) and `converter-options` (array)</td></tr>
|
318 |
+
</table>
|
319 |
+
|
320 |
+
Stack implements the functionality you know from `WebPConvert::convert`. In fact, all `WebPConvert::convert` does is to call `Stack::convert($source, $destination, $options, $logger);`
|
321 |
+
|
322 |
+
It has two special options: `converters` and `converter-options`. You can read about those in `docs/api/convert.md`
|
vendor/rosell-dk/webp-convert/docs/v1.3/converting/convert.md
ADDED
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# API: The convert() method
|
2 |
+
|
3 |
+
**WebPConvert::convert($source, $destination, $options, $logger)**
|
4 |
+
|
5 |
+
| Parameter | Type | Description |
|
6 |
+
| ---------------- | ------- | ------------------------------------------------------------------------------------------ |
|
7 |
+
| `$source` | String | Absolute path to source image (only forward slashes allowed) |
|
8 |
+
| `$destination` | String | Absolute path to converted image (only forward slashes allowed) |
|
9 |
+
| `$options` (optional) | Array | Array of conversion (option) options |
|
10 |
+
| `$logger` (optional) | Baselogger | Information about the conversion process will be passed to this object. Read more below |
|
11 |
+
|
12 |
+
Returns true if success or false if no converters are *operational*. If any converter seems to have its requirements met (are *operational*), but fails anyway, and no other converters in the stack could convert the image, an the exception from that converter is rethrown (either *ConverterFailedException* or *ConversionDeclinedException*). Exceptions are also thrown if something is wrong entirely (*InvalidFileExtensionException*, *TargetNotFoundException*, *ConverterNotFoundException*, *CreateDestinationFileException*, *CreateDestinationFolderException*, or any unanticipated exceptions thrown by the converters).
|
13 |
+
|
14 |
+
### Available options for all converters
|
15 |
+
|
16 |
+
Many options correspond to options of *cwebp*. These are documented [here](https://developers.google.com/speed/webp/docs/cwebp)
|
17 |
+
|
18 |
+
|
19 |
+
| Option | Type | Default | Description |
|
20 |
+
| ----------------- | ------- | -------------------------- | -------------------------------------------------------------------- |
|
21 |
+
| quality | An integer between 0-100, or "auto" | "auto" | Lossy quality of converted image (JPEG only - PNGs are always losless).<br><br> If set to "auto", *WebPConvert* will try to determine the quality of the JPEG (this is only possible, if Imagick or GraphicsMagic is installed). If successfully determined, the quality of the webp will be set to the same as that of the JPEG. however not to more than specified in the new `max-quality` option. If quality cannot be determined, quality will be set to what is specified in the new `default-quality` option (however, if you use the *wpc* converter, it will also get a shot at detecting the quality) |
|
22 |
+
| max-quality | An integer between 0-100 | 85 | See the `quality` option. Only relevant, when quality is set to "auto".
|
23 |
+
| default-quality | An integer between 0-100 | 75 | See the `quality` option. Only relevant, when quality is set to "auto".
|
24 |
+
| metadata | String | 'none' | Valid values: all, none, exif, icc, xmp. Note: Only *cwebp* supports all values. *gd* will always remove all metadata. *ewww*, *imagick* and *gmagick* can either strip all, or keep all (they will keep all, unless metadata is set to *none*) |
|
25 |
+
| lossless | Boolean | false ("auto" for pngs in 2.0) | Encode the image without any loss. The option is ignored for PNG's (forced true). In 2.0, it can also be "auto", and it is not forced to anything - rather it deafaults to false for Jpegs and "auto" for PNGs |
|
26 |
+
| converters | Array | ['cwebp', 'gd', 'imagick'] | Specify conversion methods to use, and their order. Also optionally set converter options (see below) |
|
27 |
+
| converter-options | Array | [] | Set options of the individual converters (see below) |
|
28 |
+
| jpeg | Array | null | These options will be merged into the other options when source is jpeg |
|
29 |
+
| png | Array | null | These options will be merged into the other options when source is jpeg |
|
30 |
+
| skip (new in 2.0) | Boolean | false | If true, conversion will be skipped (ie for skipping png conversion for some converters) |
|
31 |
+
| skip-png (removed in 2.0) | Boolean | false | If true, conversion will be skipped for png (ie for skipping png conversion for some converters) |
|
32 |
+
|
33 |
+
#### More on quality=auto
|
34 |
+
Unfortunately, *libwebp* does not provide a way to use the same quality for the converted image, as for source. This feature is implemented by *imagick* and *gmagick*. No matter which conversion method you choose, if you set *quality* to *auto*, our library will try to detect the quality of the source file using one of these libraries. If this isn't available, it will revert to the value set in the *default-quality* option (75 per default). *However*, with the *wpc* converter you have a second chance: If quality cannot be detected locally, it will send quality="auto" to *wpc*.
|
35 |
+
|
36 |
+
The bottom line is: If you do not have imagick or gmagick installed on your host (and have no way to install it), your best option quality-wise is to install *wpc* on a server that you do have access to, and connect to that. However,... read on:
|
37 |
+
|
38 |
+
**How much does it matter?**
|
39 |
+
The effect of not having quality detection is that jpeg images with medium quality (say 50) will be converted with higher quality (say 75). Converting a q=50 to a q=50 would typically result in a ~60% reduction. But converting it to q=75 will only result in a ~45% reduction. When converting low quality jpeg images, it gets worse. Converting q=30 to q=75 only achieves ~25% reduction.
|
40 |
+
|
41 |
+
I guess it is a rare case having jpeg images in low quality. Even having middle quality is rare, as there seems to have been a tendency to choose higher quality than actually needed for web. So, in many cases, the impact of not having quality detection is minor. If you set the *default-quality* a bit low, ie 65, you will further minimize the effect.
|
42 |
+
|
43 |
+
To determine if *webp-convert* is able to autodetect quality on your system, run a conversion with the *$logger* parameter set to `new EchoLogger()` (see api).
|
44 |
+
|
45 |
+
#### More on the `converter-options` option
|
46 |
+
You use this option to set options for the individual converters. Example:
|
47 |
+
|
48 |
+
```
|
49 |
+
'converter-options' => [
|
50 |
+
'ewww' => [
|
51 |
+
'key' => 'your-api-key-here'
|
52 |
+
],
|
53 |
+
'wpc' => [
|
54 |
+
'url' => 'https://example.com/wpc.php',
|
55 |
+
'secret' => 'my dog is white'
|
56 |
+
]
|
57 |
+
]
|
58 |
+
```
|
59 |
+
Besides options that are special to a converter, you can also override general options. For example, you may generally want the `max-quality` to be 85, but for a single converter, you would like it to be 100 (sorry, it is hard to come up with a useful example).
|
60 |
+
|
61 |
+
#### More on the `converters` option
|
62 |
+
The *converters* option specifies the conversion methods to use and their order. But it can also be used as an alternative way of setting converter options. Usually, you probably want to use the *converter-options* for that, but there may be cases where it is more convenient to specify them here. Also, specifying here allows you to put the same converter method to the stack multiple times, with different options (this could for example be used to have an extra *ewww* converter as a fallback).
|
63 |
+
|
64 |
+
Example:
|
65 |
+
```
|
66 |
+
WebPConvert::convert($source, $destination, [
|
67 |
+
'converters' => [
|
68 |
+
'cwebp',
|
69 |
+
'imagick',
|
70 |
+
[
|
71 |
+
'converter' => 'ewww',
|
72 |
+
'options' => [
|
73 |
+
'key' => 'your api key here',
|
74 |
+
],
|
75 |
+
],
|
76 |
+
];
|
77 |
+
)
|
78 |
+
```
|
79 |
+
In 2.0, it will be possible to use your own custom converter. Instead of the "converter id" (ie "ewww"), specify the full class name of your custom converter. Ie '\\MyProject\\BraveConverter'. The converter must extend `\WebPConvert\Convert\Converters\AbstractConverters\AbstractConverter` and you must implement `doConvert()` and the define the extra options it takes (check out how it is done in the build-in converters).
|
80 |
+
|
81 |
+
### More on the `$logger` parameter
|
82 |
+
WebPConvert and the individual converters can provide information regarding the conversion process. Per default (when the parameter isn't provided), they write this to `\WebPConvert\Loggers\VoidLogger`, which does nothing with it.
|
83 |
+
In order to get this information echoed out, you can use `\WebPConvert\Loggers\EchoLogger` - like this:
|
84 |
+
|
85 |
+
```php
|
86 |
+
use WebPConvert\Loggers\EchoLogger;
|
87 |
+
|
88 |
+
WebPConvert::convert($source, $destination, $options, new EchoLogger());
|
89 |
+
```
|
90 |
+
|
91 |
+
In order to do something else with the information (perhaps write it to a log file?), you can extend `\WebPConvert\Loggers\BaseLogger`.
|
92 |
+
|
93 |
+
## Converters
|
94 |
+
In the most basic design, a converter consists of a static convert function which takes the same arguments as `WebPConvert::convert`. Its job is then to convert `$source` to WebP and save it at `$destination`, preferably taking the options specified in $options into account.
|
95 |
+
|
96 |
+
The converters may be called directly. But you probably don't want to do that, as it really doesn't hurt having other converters ready to take over, in case your preferred converter should fail.
|
vendor/rosell-dk/webp-convert/docs/v1.3/converting/converters.md
ADDED
@@ -0,0 +1,322 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# The webp converters
|
2 |
+
|
3 |
+
## The converters at a glance
|
4 |
+
When it comes to webp conversion, there is actually only one library in town: *libwebp* from Google. All conversion methods below ultimately uses that very same library for conversion. This means that it does not matter much, which conversion method you use. Whatever works. There is however one thing to take note of, if you set *quality* to *auto*, and your system cannot determine the quality of the source (this requires imagick or gmagick), and you do not have access to install those, then the only way to get quality-detection is to connect to a *wpc* cloud converter. However, with *cwebp*, you can specify the desired reduction (the *size-in-percentage* option) - at the cost of doubling the conversion time. Read more about those considerations in the API.
|
5 |
+
|
6 |
+
Speed-wise, there is too little difference for it to matter, considering that images usually needs to be converted just once. Anyway, here are the results: *cweb* is the fastest (with method=3). *gd* is right behind, merely 3% slower than *cwebp*. *gmagick* are third place, ~8% slower than *cwebp*. *imagick* comes in ~22% slower than *cwebp*. *ewww* depends on connection speed. On my *digital ocean* account, it takes ~2 seconds to upload, convert, and download a tiny image (10 times longer than the local *cwebp*). A 1MB image however only takes ~4.5 seconds to upload, convert and download (1.5 seconds longer). A 2 MB image takes ~5 seconds to convert (only 16% longer than my *cwebp*). The *ewww* thus converts at a very decent speeds. Probably faster than your average shared host. If multiple big images needs to be converted at the same time, *ewww* will probably perform much better than the local converters.
|
7 |
+
|
8 |
+
[`cwebp`](#cwebp) works by executing the *cwebp* binary from Google, which is build upon the *libwebp* (also from Google). That library is actually the only library in town for generating webp images, which means that the other conversion methods ultimately uses that very same library. Which again means that the results using the different methods are very similar. However, with *cwebp*, we have more parameters to tweak than with the rest. We for example have the *method* option, which controls the trade off between encoding speed and the compressed file size and quality. Setting this to max, we can squeeze the images a few percent extra - without loosing quality (the converter is still pretty fast, so in most cases it is probably worth it).
|
9 |
+
|
10 |
+
Of course, as we here have to call a binary directly, *cwebp* requires the *exec* function to be enabled, and that the webserver user is allowed to execute the `cwebp` binary (either at known system locations, or one of the precompiled binaries, that comes with this library).
|
11 |
+
|
12 |
+
[`vips`](#vips) (**new in 2.0**) works by using the vips extension, if available. Vips is great! It offers many webp options, it is fast and installation is easier than imagick and gd, as it does not need to be configured for webp support.
|
13 |
+
|
14 |
+
[`imagick`](#imagick) does not support any special webp options, but is at least able to strip all metadata, if metadata is set to none. Imagick has a very nice feature - that it is able to detect the quality of a jpeg file. This enables it to automatically use same quality for destination as for source, which eliminates the risk of setting quality higher for the destination than for source (the result of that is that the file size gets higher, but the quality remains the same). As the other converters lends this capability from Imagick, this is however no reason for using Imagick rather than the other converters. Requirements: Imagick PHP extension compiled with WebP support
|
15 |
+
|
16 |
+
[`gmagick`](#gmagick) uses the *gmagick* extension. It is very similar to *imagick*. Requirements: Gmagick PHP extension compiled with WebP support.
|
17 |
+
|
18 |
+
[`gd`](#gd) uses the *Gd* extension to do the conversion. The *Gd* extension is pretty common, so the main feature of this converter is that it may work out of the box. It does not support any webp options, and does not support stripping metadata. Requirements: GD PHP extension compiled with WebP support.
|
19 |
+
|
20 |
+
[`wpc`](#wpc) is an open source cloud service for converting images to webp. To use it, you must either install [webp-convert-cloud-service](https://github.com/rosell-dk/webp-convert-cloud-service) directly on a remote server, or install the Wordpress plugin, [WebP Express](https://github.com/rosell-dk/webp-express) in Wordpress. Btw: Beware that upload limits will prevent conversion of big images. The converter checks your *php.ini* settings and abandons upload right away, if an image is larger than your *upload_max_filesize* or your *post_max_size* setting. Requirements: Access to a running service. The service can be installed [directly](https://github.com/rosell-dk/webp-convert-cloud-service) or by using [this Wordpress plugin](https://wordpress.org/plugins/webp-express/)
|
21 |
+
|
22 |
+
[`ewww`](#ewww) is also a cloud service. Not free, but cheap enough to be considered *practically* free. It supports lossless encoding, but this cannot be controlled. *Ewww* always uses lossy encoding for jpeg and lossless for png. For jpegs this is usually a good choice, however, many pngs are compressed better using lossy encoding. As lossless cannot be controlled, the "lossless:auto" option cannot be used for automatically trying both lossy and lossless and picking the smallest file. Also, unfortunately, *ewww* does not support quality=auto, like *wpc*, and it does not support *size-in-percentage* like *cwebp*, either. I have requested such features, and he is considering... As with *wpc*, beware of upload limits. Requirements: A key to the *EWWW Image Optimizer* cloud service. Can be purchaced [here](https://ewww.io/plans/)
|
23 |
+
|
24 |
+
[`stack`](#stack) takes a stack of converters and tries it from the top, until success. The main convert method actually calls this converter. Stacks within stacks are supported (not really needed, though).
|
25 |
+
|
26 |
+
|
27 |
+
**Summary:**
|
28 |
+
|
29 |
+
| | cwebp | vips | imagickbinary | imagick / gmagick | gd | ewww |
|
30 |
+
| ------------------------------------------ | --------- | ------ | -------------- | ----------------- | --------- | ------ |
|
31 |
+
| supports lossless encoding ? | yes | yes | yes | no | no | yes |
|
32 |
+
| supports lossless auto ? | yes | yes | yes | no | no | no |
|
33 |
+
| supports near-lossless ? | yes | yes | no | no | no | ? |
|
34 |
+
| supports metadata stripping / preserving | yes | yes | yes | yes | no | ? |
|
35 |
+
| supports setting alpha quality | yes | yes | yes | no | no | no |
|
36 |
+
| supports fixed quality (for lossy) | yes | yes | yes | yes | yes | yes |
|
37 |
+
| supports auto quality without help | no | no | yes | yes | no | no |
|
38 |
+
|
39 |
+
|
40 |
+
|
41 |
+
*WebPConvert* currently supports the following converters:
|
42 |
+
|
43 |
+
| Converter | Method | Requirements |
|
44 |
+
| ------------------------------------ | ------------------------------------------------ | -------------------------------------------------- |
|
45 |
+
| [`cwebp`](#cwebp) | Calls `cwebp` binary directly | `exec()` function *and* that the webserver user has permission to run `cwebp` binary |
|
46 |
+
| [`vips`](#vips) (new in 2.0) | Vips extension | Vips extension |
|
47 |
+
| [`imagick`](#imagick) | Imagick extension (`ImageMagick` wrapper) | Imagick PHP extension compiled with WebP support |
|
48 |
+
| [`gmagick`](#gmagick) | Gmagick extension (`ImageMagick` wrapper) | Gmagick PHP extension compiled with WebP support |
|
49 |
+
| [`gd`](#gd) | GD Graphics (Draw) extension (`LibGD` wrapper) | GD PHP extension compiled with WebP support |
|
50 |
+
| [`imagickbinary`](#imagickbinary) | Calls imagick binary directly | exec() and imagick installed and compiled with WebP support |
|
51 |
+
| [`wpc`](#wpc) | Connects to an open source cloud service | Access to a running service. The service can be installed [directly](https://github.com/rosell-dk/webp-convert-cloud-service) or by using [this Wordpress plugin](https://wordpress.org/plugins/webp-express/).
|
52 |
+
| [`ewww`](#ewww) | Connects to *EWWW Image Optimizer* cloud service | Purchasing a key |
|
53 |
+
|
54 |
+
## Installation
|
55 |
+
Instructions regarding getting the individual converters to work are [on the wiki](https://github.com/rosell-dk/webp-convert/wiki)
|
56 |
+
|
57 |
+
## cwebp
|
58 |
+
<table>
|
59 |
+
<tr><th>Requirements</th><td><code>exec()</code> function and that the webserver has permission to run `cwebp` binary (either found in system path, or a precompiled version supplied with this library)</td></tr>
|
60 |
+
<tr><th>Performance</th><td>~40-120ms to convert a 40kb image (depending on *method* option)</td></tr>
|
61 |
+
<tr><th>Reliability</th><td>No problems detected so far!</td></tr>
|
62 |
+
<tr><th>Availability</th><td>According to ewww docs, requirements are met on surprisingly many webhosts. Look <a href="https://docs.ewww.io/article/43-supported-web-hosts">here</a> for a list</td></tr>
|
63 |
+
<tr><th>General options supported</th><td>All (`quality`, `metadata`, `lossless`)</td></tr>
|
64 |
+
<tr><th>Extra options</th><td>`method` (0-6)<br>`use-nice` (boolean)<br>`try-common-system-paths` (boolean)<br> `try-supplied-binary-for-os` (boolean)<br>`autofilter` (boolean)<br>`size-in-percentage` (number / null)<br>`command-line-options` (string)<br>`low-memory` (boolean)</td></tr>
|
65 |
+
</table>
|
66 |
+
|
67 |
+
[cwebp](https://developers.google.com/speed/webp/docs/cwebp) is a WebP conversion command line converter released by Google. Our implementation ships with precompiled binaries for Linux, FreeBSD, WinNT, Darwin and SunOS. If however a cwebp binary is found in a usual location, that binary will be preferred. It is executed with [exec()](http://php.net/manual/en/function.exec.php).
|
68 |
+
|
69 |
+
In more detail, the implementation does this:
|
70 |
+
- It is tested whether cwebp is available in a common system path (eg `/usr/bin/cwebp`, ..)
|
71 |
+
- If not, then supplied binary is selected from `Converters/Binaries` (according to OS) - after validating checksum
|
72 |
+
- Command-line options are generated from the options
|
73 |
+
- If [`nice`]( https://en.wikipedia.org/wiki/Nice_(Unix)) command is found on host, binary is executed with low priority in order to save system resources
|
74 |
+
- Permissions of the generated file are set to be the same as parent folder
|
75 |
+
|
76 |
+
### Cwebp options
|
77 |
+
|
78 |
+
The following options are supported, besides the general options (such as quality, lossless etc):
|
79 |
+
|
80 |
+
| Option | Type | Default |
|
81 |
+
| -------------------------- | ------------------------- | -------------------------- |
|
82 |
+
| autofilter | boolean | false |
|
83 |
+
| command-line-options | string | '' |
|
84 |
+
| low-memory | boolean | false |
|
85 |
+
| method | integer (0-6) | 6 |
|
86 |
+
| near-lossless | integer (0-100) | 60 |
|
87 |
+
| size-in-percentage | integer (0-100) (or null) | null |
|
88 |
+
| rel-path-to-precompiled-binaries | string | './Binaries' |
|
89 |
+
| size-in-percentage | number (or null) | is_null |
|
90 |
+
| try-common-system-paths | boolean | true |
|
91 |
+
| try-supplied-binary-for-os | boolean | true |
|
92 |
+
| use-nice | boolean | false |
|
93 |
+
|
94 |
+
Descriptions (only of some of the options):
|
95 |
+
|
96 |
+
#### the `autofilter` option
|
97 |
+
Turns auto-filter on. This algorithm will spend additional time optimizing the filtering strength to reach a well-balanced quality. Unfortunately, it is extremely expensive in terms of computation. It takes about 5-10 times longer to do a conversion. A 1MB picture which perhaps typically takes about 2 seconds to convert, will takes about 15 seconds to convert with auto-filter. So in most cases, you will want to leave this at its default, which is off.
|
98 |
+
|
99 |
+
#### the `command-line-options` option
|
100 |
+
This allows you to set any parameter available for cwebp in the same way as you would do when executing *cwebp*. You could ie set it to "-sharpness 5 -mt -crop 10 10 40 40". Read more about all the available parameters in [the docs](https://developers.google.com/speed/webp/docs/cwebp)
|
101 |
+
|
102 |
+
#### the `low-memory` option
|
103 |
+
Reduce memory usage of lossy encoding at the cost of ~30% longer encoding time and marginally larger output size. Default: `false`. Read more in [the docs](https://developers.google.com/speed/webp/docs/cwebp). Default: *false*
|
104 |
+
|
105 |
+
#### The `method` option
|
106 |
+
This parameter controls the trade off between encoding speed and the compressed file size and quality. Possible values range from 0 to 6. 0 is fastest. 6 results in best quality.
|
107 |
+
|
108 |
+
#### the `near-lossless` option
|
109 |
+
Specify the level of near-lossless image preprocessing. This option adjusts pixel values to help compressibility, but has minimal impact on the visual quality. It triggers lossless compression mode automatically. The range is 0 (maximum preprocessing) to 100 (no preprocessing). The typical value is around 60. Read more [here](https://groups.google.com/a/webmproject.org/forum/#!topic/webp-discuss/0GmxDmlexek). Default: 60
|
110 |
+
|
111 |
+
#### The `size-in-percentage` option
|
112 |
+
This option sets the file size, *cwebp* should aim for, in percentage of the original. If you for example set it to *45*, and the source file is 100 kb, *cwebp* will try to create a file with size 45 kb (we use the `-size` option). This is an excellent alternative to the "quality:auto" option. If the quality detection isn't working on your system (and you do not have the rights to install imagick or gmagick), you should consider using this options instead. *Cwebp* is generally able to create webp files with the same quality at about 45% the size. So *45* would be a good choice. The option overrides the quality option. And note that it slows down the conversion - it takes about 2.5 times longer to do a conversion this way, than when quality is specified. Default is *off* (null)
|
113 |
+
|
114 |
+
|
115 |
+
#### final words on cwebp
|
116 |
+
The implementation is based on the work of Shane Bishop for his plugin, [EWWW Image Optimizer](https://ewww.io). Thanks for letting us do that!
|
117 |
+
|
118 |
+
See [the wiki](https://github.com/rosell-dk/webp-convert/wiki/Installing-cwebp---using-official-precompilations) for instructions regarding installing cwebp or using official precompilations.
|
119 |
+
|
120 |
+
## vips
|
121 |
+
<table>
|
122 |
+
<tr><th>Requirements</th><td>Vips extension</td></tr>
|
123 |
+
<tr><th>Performance</th><td>Great</td></tr>
|
124 |
+
<tr><th>Reliability</th><td>No problems detected so far!</td></tr>
|
125 |
+
<tr><th>Availability</th><td>Not that widespread yet, but gaining popularity</td></tr>
|
126 |
+
<tr><th>General options supported</th><td>All (`quality`, `metadata`, `lossless`)</td></tr>
|
127 |
+
<tr><th>Extra options</th><td>`smart-subsample`(boolean)<br>`alpha-quality`(0-100)<br>`near-lossless` (0-100)<br> `preset` (0-6)</td></tr>
|
128 |
+
</table>
|
129 |
+
|
130 |
+
For installation instructions, go [here](https://github.com/libvips/php-vips-ext).
|
131 |
+
|
132 |
+
The options are described [here](https://jcupitt.github.io/libvips/API/current/VipsForeignSave.html#vips-webpsave)
|
133 |
+
|
134 |
+
*near-lossless* is however an integer (0-100), in order to have the option behave like in cwebp.
|
135 |
+
|
136 |
+
|
137 |
+
|
138 |
+
## wpc
|
139 |
+
*WebPConvert Cloud Service*
|
140 |
+
|
141 |
+
<table>
|
142 |
+
<tr><th>Requirements</th><td>Access to a server with [webp-convert-cloud-service](https://github.com/rosell-dk/webp-convert-cloud-service) installed, <code>cURL</code> and PHP >= 5.5.0</td></tr>
|
143 |
+
<tr><th>Performance</th><td>Depends on the server where [webp-convert-cloud-service](https://github.com/rosell-dk/webp-convert-cloud-service) is set up, and the speed of internet connections. But perhaps ~1000ms to convert a 40kb image</td></tr>
|
144 |
+
<tr><th>Reliability</th><td>Great (depends on the reliability on the server where it is set up)</td></tr>
|
145 |
+
<tr><th>Availability</th><td>Should work on <em>almost</em> any webhost</td></tr>
|
146 |
+
<tr><th>General options supported</th><td>All (`quality`, `metadata`, `lossless`)</td></tr>
|
147 |
+
<tr><th>Extra options (old api)</th><td>`url`, `secret`</td></tr>
|
148 |
+
<tr><th>Extra options (new api)</th><td>`url`, `api-version`, `api-key`, `crypt-api-key-in-transfer`</td></tr>
|
149 |
+
</table>
|
150 |
+
|
151 |
+
[wpc](https://github.com/rosell-dk/webp-convert-cloud-service) is an open source cloud service. You do not buy a key, you set it up on a server, or you set up [the Wordpress plugin](https://wordpress.org/plugins/webp-express/). As WebPConvert Cloud Service itself is based on WebPConvert, all options are supported.
|
152 |
+
|
153 |
+
To use it, you need to set the `converter-options` (to add url etc).
|
154 |
+
|
155 |
+
#### Example, where api-key is not crypted, on new API:
|
156 |
+
|
157 |
+
```php
|
158 |
+
WebPConvert::convert($source, $destination, [
|
159 |
+
'max-quality' => 80,
|
160 |
+
'converters' => ['cwebp', 'wpc'],
|
161 |
+
'converter-options' => [
|
162 |
+
'wpc' => [
|
163 |
+
'api-version' => 1, /* from wpc release 1.0.0 */
|
164 |
+
'url' => 'http://example.com/wpc.php',
|
165 |
+
'api-key' => 'my dog is white',
|
166 |
+
'crypt-api-key-in-transfer' => false
|
167 |
+
]
|
168 |
+
]
|
169 |
+
));
|
170 |
+
```
|
171 |
+
|
172 |
+
#### Example, where api-key is crypted:
|
173 |
+
|
174 |
+
```php
|
175 |
+
|
176 |
+
WebPConvert::convert($source, $destination, [
|
177 |
+
'max-quality' => 80,
|
178 |
+
'converters' => ['cwebp', 'wpc'],
|
179 |
+
'converter-options' => [
|
180 |
+
'wpc' => [
|
181 |
+
'api-version' => 1,
|
182 |
+
'url' => 'https://example.com/wpc.php',
|
183 |
+
'api-key' => 'my dog is white',
|
184 |
+
'crypt-api-key-in-transfer' => true
|
185 |
+
],
|
186 |
+
]
|
187 |
+
));
|
188 |
+
```
|
189 |
+
|
190 |
+
In 2.0, you can alternatively set the api key and urls through through the *WPC_API_KEY* and *WPC_API_URL* environment variables. This is a safer place to store it.
|
191 |
+
|
192 |
+
To set an environment variable in Apache, you can use the `SetEnv` directory. Ie, place something like the following in your virtual host / or .htaccess file (replace the key with the one you purchased!)
|
193 |
+
|
194 |
+
```
|
195 |
+
SetEnv WPC_API_KEY my-dog-is-dashed
|
196 |
+
SetEnv WPC_API_URL https://wpc.example.com/wpc.php
|
197 |
+
```
|
198 |
+
|
199 |
+
|
200 |
+
#### Example, old API:
|
201 |
+
|
202 |
+
```php
|
203 |
+
WebPConvert::convert($source, $destination, [
|
204 |
+
'max-quality' => 80,
|
205 |
+
'converters' => ['cwebp', 'wpc'],
|
206 |
+
'converter-options' => [
|
207 |
+
'wpc' => [
|
208 |
+
'url' => 'https://example.com/wpc.php',
|
209 |
+
'secret' => 'my dog is white',
|
210 |
+
],
|
211 |
+
]
|
212 |
+
));
|
213 |
+
```
|
214 |
+
|
215 |
+
|
216 |
+
## ewww
|
217 |
+
|
218 |
+
<table>
|
219 |
+
<tr><th>Requirements</th><td>Valid EWWW Image Optimizer <a href="https://ewww.io/plans/">API key</a>, <code>cURL</code> and PHP >= 5.5.0</td></tr>
|
220 |
+
<tr><th>Performance</th><td>~1300ms to convert a 40kb image</td></tr>
|
221 |
+
<tr><th>Reliability</th><td>Great (but, as with any cloud service, there is a risk of downtime)</td></tr>
|
222 |
+
<tr><th>Availability</th><td>Should work on <em>almost</em> any webhost</td></tr>
|
223 |
+
<tr><th>General options supported</th><td>`quality`, `metadata` (partly)</td></tr>
|
224 |
+
<tr><th>Extra options</th><td>`key`</td></tr>
|
225 |
+
</table>
|
226 |
+
|
227 |
+
EWWW Image Optimizer is a very cheap cloud service for optimizing images. After purchasing an API key, add the converter in the `extra-converters` option, with `key` set to the key. Be aware that the `key` should be stored safely to avoid exploitation - preferably in the environment, ie with [dotenv](https://github.com/vlucas/phpdotenv).
|
228 |
+
|
229 |
+
The EWWW api doesn't support the `lossless` option, but it does automatically convert PNG's losslessly. Metadata is either all or none. If you have set it to something else than one of these, all metadata will be preserved.
|
230 |
+
|
231 |
+
In more detail, the implementation does this:
|
232 |
+
- Validates that there is a key, and that `curl` extension is working
|
233 |
+
- Validates the key, using the [/verify/ endpoint](https://ewww.io/api/) (in order to [protect the EWWW service from unnecessary file uploads, when key has expired](https://github.com/rosell-dk/webp-convert/issues/38))
|
234 |
+
- Converts, using the [/ endpoint](https://ewww.io/api/).
|
235 |
+
|
236 |
+
<details>
|
237 |
+
<summary><strong>Roadmap</strong> 👁</summary>
|
238 |
+
|
239 |
+
The converter could be improved by using `fsockopen` when `cURL` is not available - which is extremely rare. PHP >= 5.5.0 is also widely available (PHP 5.4.0 reached end of life [more than two years ago!](http://php.net/supported-versions.php)).
|
240 |
+
</details>
|
241 |
+
|
242 |
+
#### Example:
|
243 |
+
|
244 |
+
```php
|
245 |
+
WebPConvert::convert($source, $destination, [
|
246 |
+
'max-quality' => 80,
|
247 |
+
'converters' => ['gd', 'ewww'],
|
248 |
+
'converter-options' => [
|
249 |
+
'ewww' => [
|
250 |
+
'key' => 'your-api-key-here'
|
251 |
+
],
|
252 |
+
]
|
253 |
+
));
|
254 |
+
```
|
255 |
+
In 2.0, you can alternatively set the api key by through the *EWWW_API_KEY* environment variable. This is a safer place to store it.
|
256 |
+
|
257 |
+
To set an environment variable in Apache, you can use the `SetEnv` directory. Ie, place something like the following in your virtual host / or .htaccess file (replace the key with the one you purchased!)
|
258 |
+
|
259 |
+
```
|
260 |
+
SetEnv EWWW_API_KEY sP3LyPpsKWZy8CVBTYegzEGN6VsKKKKA
|
261 |
+
```
|
262 |
+
|
263 |
+
## gd
|
264 |
+
|
265 |
+
<table>
|
266 |
+
<tr><th>Requirements</th><td>GD PHP extension and PHP >= 5.5.0 (compiled with WebP support)</td></tr>
|
267 |
+
<tr><th>Performance</th><td>~30ms to convert a 40kb image</td></tr>
|
268 |
+
<tr><th>Reliability</th><td>Not sure - I have experienced corrupted images, but cannot reproduce</td></tr>
|
269 |
+
<tr><th>Availability</th><td>Unfortunately, according to <a href="https://stackoverflow.com/questions/25248382/how-to-create-a-webp-image-in-php">this link</a>, WebP support on shared hosts is rare.</td></tr>
|
270 |
+
<tr><th>General options supported</th><td>`quality`</td></tr>
|
271 |
+
<tr><th>Extra options</th><td>`skip-pngs`</td></tr>
|
272 |
+
</table>
|
273 |
+
|
274 |
+
[imagewebp](http://php.net/manual/en/function.imagewebp.php) is a function that comes with PHP (>5.5.0), *provided* that PHP has been compiled with WebP support.
|
275 |
+
|
276 |
+
`gd` neither supports copying metadata nor exposes any WebP options. Lacking the option to set lossless encoding results in poor encoding of PNGs - the filesize is generally much larger than the original. For this reason, PNG conversion is *disabled* by default, but it can be enabled my setting `skip-pngs` option to `false`.
|
277 |
+
|
278 |
+
Installaition instructions are [available in the wiki](https://github.com/rosell-dk/webp-convert/wiki/Installing-Gd-extension).
|
279 |
+
|
280 |
+
<details>
|
281 |
+
<summary><strong>Known bugs</strong> 👁</summary>
|
282 |
+
Due to a [bug](https://bugs.php.net/bug.php?id=66590), some versions sometimes created corrupted images. That bug can however easily be fixed in PHP (fix was released [here](https://stackoverflow.com/questions/30078090/imagewebp-php-creates-corrupted-webp-files)). However, I have experienced corrupted images *anyway* (but cannot reproduce that bug). So use this converter with caution. The corrupted images look completely transparent in Google Chrome, but have the correct size.
|
283 |
+
</details>
|
284 |
+
|
285 |
+
## imagick
|
286 |
+
|
287 |
+
<table>
|
288 |
+
<tr><th>Requirements</th><td>Imagick PHP extension (compiled with WebP support)</td></tr>
|
289 |
+
<tr><th>Quality</th><td>Poor. [See this issue]( https://github.com/rosell-dk/webp-convert/issues/43)</td></tr>
|
290 |
+
<tr><th>General options supported</th><td>`quality`</td></tr>
|
291 |
+
<tr><th>Extra options</th><td>None</td></tr>
|
292 |
+
<tr><th>Performance</th><td>~20-320ms to convert a 40kb image</td></tr>
|
293 |
+
<tr><th>Reliability</th><td>No problems detected so far</td></tr>
|
294 |
+
<tr><th>Availability</th><td>Probably only available on few shared hosts (if any)</td></tr>
|
295 |
+
</table>
|
296 |
+
|
297 |
+
WebP conversion with `imagick` is fast and [exposes many WebP options](http://www.imagemagick.org/script/webp.php). Unfortunately, WebP support for the `imagick` extension is pretty uncommon. At least not on the systems I have tried (Ubuntu 16.04 and Ubuntu 17.04). But if installed, it works great and has several WebP options.
|
298 |
+
|
299 |
+
See [this page](https://github.com/rosell-dk/webp-convert/wiki/Installing-Imagick-extension) in the Wiki for instructions on installing the extension.
|
300 |
+
|
301 |
+
## imagickbinary
|
302 |
+
<table>
|
303 |
+
<tr><th>Requirements</th><td><code>exec()</code> function and that imagick is installed on webserver, compiled with webp support</td></tr>
|
304 |
+
<tr><th>Performance</th><td>just fine</td></tr>
|
305 |
+
<tr><th>Reliability</th><td>No problems detected so far!</td></tr>
|
306 |
+
<tr><th>Availability</th><td>Not sure</td></tr>
|
307 |
+
<tr><th>General options supported</th><td>`quality`</td></tr>
|
308 |
+
<tr><th>Extra options</th><td>`use-nice` (boolean)</td></tr>
|
309 |
+
</table>
|
310 |
+
|
311 |
+
This converter tryes to execute `convert source.jpg webp:destination.jpg.webp`.
|
312 |
+
|
313 |
+
## stack
|
314 |
+
|
315 |
+
<table>
|
316 |
+
<tr><th>General options supported</th><td>all (passed to the converters in the stack )</td></tr>
|
317 |
+
<tr><th>Extra options</th><td>`converters` (array) and `converter-options` (array)</td></tr>
|
318 |
+
</table>
|
319 |
+
|
320 |
+
Stack implements the functionality you know from `WebPConvert::convert`. In fact, all `WebPConvert::convert` does is to call `Stack::convert($source, $destination, $options, $logger);`
|
321 |
+
|
322 |
+
It has two special options: `converters` and `converter-options`. You can read about those in `docs/api/convert.md`
|
vendor/rosell-dk/webp-convert/docs/v1.3/serving/convert-and-serve.md
ADDED
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# API: The WebPConvert::convertAndServe() method
|
2 |
+
|
3 |
+
*NOTE:* In 2.0, the method is renamed to *serveConverted* ("convertAndServe" was implying that a conversion was always made, but the method simply serves destination if it exists and is smaller and newer than source)
|
4 |
+
|
5 |
+
The method tries to serve a converted image. If destination already exists, the already converted image will be served. Unless the original is newer or smaller. If the method fails, it will serve original image, a 404, or whatever the 'fail' option is set to.
|
6 |
+
|
7 |
+
**WebPConvert::convertAndServe($source, $destination, $options)**
|
8 |
+
|
9 |
+
| Parameter | Type | Description |
|
10 |
+
| ---------------- | ------- | ------------------------------------------------------------------- |
|
11 |
+
| `$source` | String | Absolute path to source image (only forward slashes allowed) |
|
12 |
+
| `$destination` | String | Absolute path to converted image (only forward slashes allowed) |
|
13 |
+
| `$options` | Array | Array of options (see below) |
|
14 |
+
|
15 |
+
## The *$options* argument
|
16 |
+
The options argument is a named array. Besides the options described below, you can also use any options that the *convert* method takes (if a fresh convertion needs to be created, this method will call the *convert* method and hand over the options argument)
|
17 |
+
|
18 |
+
### *convert*
|
19 |
+
Conversion options, handed over to the convert method, in case a conversion needs to be made. The convert options are documented [here](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md).
|
20 |
+
|
21 |
+
### *fail*
|
22 |
+
Indicate what to do, in case of normal conversion failure.
|
23 |
+
Default value: *"original"*
|
24 |
+
|
25 |
+
| Possible values | Meaning |
|
26 |
+
| ----------------- | ----------------------------------------------- |
|
27 |
+
| "serve-original" | Serve the original image. |
|
28 |
+
| "404" | Serve 404 status (not found) |
|
29 |
+
| "report-as-image" | Serve an image with text explaining the problem |
|
30 |
+
| "report" | Serve a textual report explaining the problem |
|
31 |
+
|
32 |
+
### *fail-when-original-unavailable*
|
33 |
+
Possible values: Same as above, except that "original" is not an option.
|
34 |
+
Default value: *"404"*
|
35 |
+
|
36 |
+
### *show-report*
|
37 |
+
Produce a report rather than serve an image.
|
38 |
+
Default value: *false*
|
39 |
+
|
40 |
+
### *reconvert*
|
41 |
+
Force a conversion, discarding existing converted image (if any).
|
42 |
+
Default value: *false*
|
43 |
+
|
44 |
+
### *serve-original*
|
45 |
+
Forces serving original image. This will skip conversion.
|
46 |
+
Default value: *false*
|
47 |
+
|
48 |
+
### *add-x-header-status*
|
49 |
+
When set to *true*, a *X-WebP-Convert-Status* header will be added describing how things went.
|
50 |
+
Default value: *true*
|
51 |
+
|
52 |
+
Depending on how things goes, the header will be set to one of the following:
|
53 |
+
- "Failed (missing source argument)"
|
54 |
+
- "Failed (source not found)""
|
55 |
+
- "Failed (missing destination argument)"
|
56 |
+
- "Reporting..."
|
57 |
+
- "Serving original image (was explicitly told to)"
|
58 |
+
- "Serving original image - because it is smaller than the converted!"
|
59 |
+
- "Serving freshly converted image (the original had changed)"
|
60 |
+
- "Serving existing converted image"
|
61 |
+
- "Converting image (handed over to WebPConvertAndServe)"
|
62 |
+
- "Serving freshly converted image"
|
63 |
+
- "Failed (could not convert image)"
|
64 |
+
|
65 |
+
### *add-vary-header*
|
66 |
+
Add a "Vary: Accept" header when an image is served. Experimental.
|
67 |
+
Default value: *true*
|
68 |
+
|
69 |
+
### *add-content-type-header*
|
70 |
+
Add a "Content-Type" header
|
71 |
+
Default value: *true*
|
72 |
+
If set, a *Content-Type* header will be added. It will be set to "image/webp" if a converted image is served, "image/jpeg" or "image/png", if the original is served or "image/gif", if an error message is served (as image). You can set it to false when debugging (to check if any errors are being outputted)
|
73 |
+
|
74 |
+
### *add-last-modified-header*
|
75 |
+
Add a "Last-Modified" header
|
76 |
+
Default value: *true*
|
77 |
+
If set, a *Last-Modified* header will be added. When a cached image is served, it will be set to the modified time of the converted file. When a fresh image is served, it is set to current time.
|
78 |
+
|
79 |
+
### *cache-control-header*
|
80 |
+
Specify a cache control header, which will be served when caching is appropriate.
|
81 |
+
Default value: "public, max-age=86400" (1 day)
|
82 |
+
Caching is "deemed appropriate", when destination is served, source is served, because it is lighter or a fresh conversion is made, due to there not being any converted image at the destination yet. Caching is not deemed appropriate when something fails, a report is requested, or the *reconvert* option have been set. Note: in version 1.3.2 and below, the *serve-original* option also prevented caching, but it no longer does. previous In those cases, standard headers will be used for preventing caching.
|
83 |
+
For your convenience, here is a little table:
|
84 |
+
|
85 |
+
| duration | max-age |
|
86 |
+
| -------- | ---------------- |
|
87 |
+
| 1 second | max-age=1 |
|
88 |
+
| 1 minute | max-age=60 |
|
89 |
+
| 1 hour | max-age=3600 |
|
90 |
+
| 1 day | max-age=86400 |
|
91 |
+
| 1 week | max-age=604800 |
|
92 |
+
| 1 month | max-age=2592000 |
|
93 |
+
| 1 year | max-age=31536000 |
|
94 |
+
|
95 |
+
To learn about the options for the Cache-Control header, go [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control)
|
96 |
+
|
97 |
+
### *error-reporting*
|
98 |
+
Set error reporting
|
99 |
+
Allowed values: *"auto"*, *"dont-mess"*, *true*, *false*
|
100 |
+
Default value: *"auto"*
|
101 |
+
|
102 |
+
If set to true, error reporting will be turned on, like this:
|
103 |
+
```
|
104 |
+
error_reporting(E_ALL);
|
105 |
+
ini_set('display_errors', 'On');
|
106 |
+
```
|
107 |
+
|
108 |
+
If set to false, error reporting will be turned off, like this:
|
109 |
+
```
|
110 |
+
error_reporting(0);
|
111 |
+
ini_set('display_errors', 'Off');
|
112 |
+
```
|
113 |
+
If set to "auto", errors will be turned off, unless the `show-report` option is set, in which case errors will be turned off.
|
114 |
+
If set to "dont-mess", error reporting will not be touched.
|
115 |
+
|
116 |
+
### *aboutToServeImageCallBack*
|
117 |
+
This callback is called right before response headers and image is served. This is a great chance to adding headers. You can stop the image and the headers from being served by returning *false*.
|
118 |
+
|
119 |
+
**Arguments:**
|
120 |
+
The first argument to the callback contains a string that tells what is about to be served. It can be 'fresh-conversion', 'destination' or 'source'.
|
121 |
+
|
122 |
+
The second argument tells you why that is served. It can be one of the following:
|
123 |
+
for 'source':
|
124 |
+
- "explicitly-told-to" (when the "serve-original" option is set)
|
125 |
+
- "source-lighter" (when original image is actually smaller than the converted)
|
126 |
+
|
127 |
+
for 'fresh-conversion':
|
128 |
+
- "explicitly-told-to" (when the "reconvert" option is set)
|
129 |
+
- "source-modified" (when source is newer than existing)
|
130 |
+
- "no-existing" (when there is no existing at the destination)
|
131 |
+
|
132 |
+
for 'destination':
|
133 |
+
- "no-reason-not-to" (it is lighter than source, its not older, and we were not told to do otherwise)
|
134 |
+
|
135 |
+
Example of callback:
|
136 |
+
```
|
137 |
+
function aboutToServeImageCallBack($servingWhat, $whyServingThis, $obj)
|
138 |
+
{
|
139 |
+
echo 'about to serve: ' . $servingWhat . '<br>';
|
140 |
+
echo 'Why? - because: ' . $whyServingThis;
|
141 |
+
return false; // Do not serve! (this also prevents any response headers from being added)
|
142 |
+
}
|
143 |
+
```
|
144 |
+
|
145 |
+
### *aboutToPerformFailActionCallback*
|
146 |
+
This callback is called right before doing the action specified in the `fail` option, or the `fail-when-original-unavailable` option. You can stop the fail action from being executod by returning *false*.
|
147 |
+
|
148 |
+
Documentation by example:
|
149 |
+
```
|
150 |
+
function aboutToPerformFailActionCallback($errorTitle, $errorDescription, $actionAboutToBeTaken, $serveConvertedObj)
|
151 |
+
{
|
152 |
+
echo '<h1>' . $errorTitle . '</h1>';
|
153 |
+
echo $errorDescription;
|
154 |
+
if (actionAboutToBeTaken == '404') {
|
155 |
+
// handle 404 differently than webp-convert would
|
156 |
+
$protocol = isset($_SERVER["SERVER_PROTOCOL"]) ? $_SERVER["SERVER_PROTOCOL"] : 'HTTP/1.0';
|
157 |
+
$serveConvertedObj->header($protocol . " 404 Not Found. We take this very seriously. Heads will roll.");
|
158 |
+
|
159 |
+
return false; // stop webp-convert from doing what it would do
|
160 |
+
}
|
161 |
+
|
162 |
+
}
|
163 |
+
```
|
164 |
+
|
165 |
+
### *require-for-conversion*
|
166 |
+
If set, makes the library 'require in' a file just before doing an actual conversion with `ConvertAndServe::convertAndServe()`. This is not needed for composer projects, as composer takes care of autoloading classes when needed.
|
167 |
+
Default value: *null*
|
vendor/rosell-dk/webp-convert/docs/v1.3/webp-on-demand/tweaks.md
ADDED
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Tweaks
|
2 |
+
|
3 |
+
## Store converted images in separate folder
|
4 |
+
|
5 |
+
In most cases, you probably want the cache of converted images to be stored in their own folder rather than have them mingled with the source files.
|
6 |
+
|
7 |
+
To have have the cache folder contain a file structure mirroring the structure of the original files, you can do this:
|
8 |
+
|
9 |
+
```php
|
10 |
+
$applicationRoot = $_SERVER["DOCUMENT_ROOT"]; // If your application is not in document root, you can change accordingly.
|
11 |
+
$imageRoot = $applicationRoot . '/webp-images'; // Change to where you want the webp images to be saved
|
12 |
+
$sourceRel = substr($source, strlen($applicationRoot));
|
13 |
+
$destination = $imageRoot . $sourceRel . '.webp';
|
14 |
+
```
|
15 |
+
|
16 |
+
If your images are stored outside document root (a rare case), you can simply use the complete absolute path:
|
17 |
+
```php
|
18 |
+
$destination = $imageRoot . $source . '.webp'; // pst: $source is an absolute path, and starts with '/'
|
19 |
+
```
|
20 |
+
This will ie store a converted image in */var/www/example.com/public_html/app/webp-images/var/www/example.com/images/logo.jpg.webp*
|
21 |
+
|
22 |
+
If your application can be configured to store outside document root, but rarely is, you can go for this structure:
|
23 |
+
|
24 |
+
```php
|
25 |
+
$docRoot = $_SERVER["DOCUMENT_ROOT"];
|
26 |
+
$imageRoot = $contentDirAbs . '/webp-images';
|
27 |
+
|
28 |
+
if (substr($source, 0, strlen($docRoot)) === $docRoot) {
|
29 |
+
// Source file is residing inside document root.
|
30 |
+
// We can store relative to that.
|
31 |
+
$sourceRel = substr($source, strlen($docRoot));
|
32 |
+
$destination = $imageRoot . '/doc-root' . $sourceRel . '.webp';
|
33 |
+
} else {
|
34 |
+
// Source file is residing outside document root.
|
35 |
+
// we must add complete path to structure
|
36 |
+
$destination = $imageRoot . '/abs' . $source . '.webp';
|
37 |
+
}
|
38 |
+
```
|
39 |
+
|
40 |
+
If you do not know the application root beforehand, and thus do not know the appropriate root for the converted images, see next tweak.
|
41 |
+
|
42 |
+
|
43 |
+
## Get the application root automatically
|
44 |
+
When you want destination files to be put in their own folder, you need to know the root of the application (the folder in which the .htaccess rules resides). In most applications, you know the root. In many cases, it is simply the document root. However, if you are writing an extension, plugin or module to a framework that can be installed in a subfolder, you may have trouble finding it. Many applications have a *index.php* in the root, which can get it with `__DIR__`. However, you do not want to run an entire bootstrap each time you serve an image. Obviously, to get around this, you can place *webp-on-demand.php* in the webroot. However, some frameworks, such as Wordpress, will not allow a plugin to put a file in the root. Now, how could we determine the application root from a file inside some subdir? Here are three suggestions:
|
45 |
+
|
46 |
+
1. You could traverse parent folders until you find a file you expect to be in application root (ie a .htaccess containing the string "webp-on-demand.php"). This should work.
|
47 |
+
2. If the rules in the *.htaccess* file are generated by your application, you probably have access to the path at generation time. You can then simply put the path in the *.htaccess*, as an extra parameter to the script (or better: the relative path from document root to the application).
|
48 |
+
3. You can use the following hack:
|
49 |
+
|
50 |
+
### The hack
|
51 |
+
The idea is to grab the URL path of the image in the *.htaccess* and pass it to the script. Assuming that the URL paths always matches the file paths, we can get the application root by subtracting that relative path to source from the absolute path to source.
|
52 |
+
|
53 |
+
In *.htaccess*, we grab the url-path by appending "&url-path=$1.$2" to the rewrite rule:
|
54 |
+
```
|
55 |
+
RewriteRule ^(.*)\.(jpe?g|png)$ webp-on-demand.php?source=%{SCRIPT_FILENAME}&url-path=$1.$2 [NC,L]
|
56 |
+
```
|
57 |
+
|
58 |
+
In the script, we can then calculate the application root like this:
|
59 |
+
|
60 |
+
```php
|
61 |
+
$applicationRoot = substr($_GET['source'], 0, -strlen($_GET['url-path']));
|
62 |
+
```
|
63 |
+
|
64 |
+
## CDN
|
65 |
+
To work properly with a CDN, a "Vary Accept" header should be added when serving images. This is a declaration that the response varies with the *Accept* header (recall that we inspect *Accept* header in the .htaccess to determine if the browsers supports webp images). If this header is missing, the CDN will see no reason to cache separate images depending on the Accept header.
|
66 |
+
|
67 |
+
Add this snippet to the *.htaccess* to make webp-on-demand work with CDN's:
|
68 |
+
|
69 |
+
```
|
70 |
+
<IfModule mod_headers.c>
|
71 |
+
SetEnvIf Request_URI "\.(jpe?g|png)" ADDVARY
|
72 |
+
|
73 |
+
# Declare that the response varies depending on the accept header.
|
74 |
+
# The purpose is to make CDN cache both original images and converted images.
|
75 |
+
Header append "Vary" "Accept" env=ADDVARY
|
76 |
+
</IfModule>
|
77 |
+
```
|
78 |
+
|
79 |
+
***Note:*** When configuring the CDN, you must make sure to set it up to forward the the "Accept" header to your origin server.
|
80 |
+
|
81 |
+
|
82 |
+
|
83 |
+
## Make .htaccess route directly to existing images
|
84 |
+
|
85 |
+
There may be a performance benefit of using the *.htaccess* file to route to already converted images, instead of letting the PHP script serve it. Note however:
|
86 |
+
- If you do the routing in .htaccess, the solution will not be able to discard converted images when original images are updated.
|
87 |
+
- Performance benefit may be insignificant (*WebPConvertAndServe* class is not autoloaded when serving existing images)
|
88 |
+
|
89 |
+
Add the following to the *.htaccess* to make it route to existing converted images. Place it above the # Redirect images to webp-on-demand.php" comment. Take care of replacing [[your-base-path]] with the directory your *.htaccess* lives in (relative to document root, and [[your-destination-root]] with the directory the converted images resides.
|
90 |
+
```
|
91 |
+
# Redirect to existing converted image (under appropriate circumstances)
|
92 |
+
RewriteCond %{HTTP_ACCEPT} image/webp
|
93 |
+
RewriteCond %{DOCUMENT_ROOT}/[[your-base-path]]/[[your-destination-root]]/$1.$2.webp -f
|
94 |
+
RewriteRule ^\/?(.*)\.(jpe?g|png)$ /[[your-base-path]]/[[your-destination-root]]/$1.$2.webp [NC,T=image/webp,L]
|
95 |
+
```
|
96 |
+
*edit:* Removed the QSD flag from the RewriteRule because it is not supported in Apache < 2.4 (and it [triggers error](https://github.com/rosell-dk/webp-express/issues/155))
|
97 |
+
|
98 |
+
### Redirect with CDN support
|
99 |
+
If you are using a CDN, and want to redirect to existing images with the .htaccess, it is a good idea to add a "Vary Accept" header. This instructs the CDN that the response varies with the *Accept* header (we do not need to do that when routing to webp-on-demand.php, because the script takes care of adding this header, when appropriate.)
|
100 |
+
|
101 |
+
You can achieve redirect with CDN support with the following rules:
|
102 |
+
```
|
103 |
+
<IfModule mod_rewrite.c>
|
104 |
+
|
105 |
+
RewriteEngine On
|
106 |
+
|
107 |
+
# Redirect to existing converted image (under appropriate circumstances)
|
108 |
+
RewriteCond %{HTTP_ACCEPT} image/webp
|
109 |
+
RewriteCond %{DOCUMENT_ROOT}/[[your-base-path]]/[[your-destination-root]]/$1.$2.webp -f
|
110 |
+
RewriteRule ^\/?(.*)\.(jpe?g|png)$ /[[your-base-path]]/[[your-destination-root]]/$1.$2.webp [NC,T=image/webp,QSD,E=WEBPACCEPT:1,L]
|
111 |
+
|
112 |
+
# Redirect images to webp-on-demand.php (if browser supports webp)
|
113 |
+
RewriteCond %{HTTP_ACCEPT} image/webp
|
114 |
+
RewriteRule ^(.*)\.(jpe?g|png)$ webp-on-demand.php?source=%{SCRIPT_FILENAME}&url-path=$1.$2 [NC,L]
|
115 |
+
|
116 |
+
</IfModule>
|
117 |
+
|
118 |
+
<IfModule mod_headers.c>
|
119 |
+
# Apache appends "REDIRECT_" in front of the environment variables, but LiteSpeed does not.
|
120 |
+
# These next line is for Apache, in order to set environment variables without "REDIRECT_"
|
121 |
+
SetEnvIf REDIRECT_WEBPACCEPT 1 WEBPACCEPT=1
|
122 |
+
|
123 |
+
# Make CDN caching possible.
|
124 |
+
# The effect is that the CDN will cache both the webp image and the jpeg/png image and return the proper
|
125 |
+
# image to the proper clients (for this to work, make sure to set up CDN to forward the "Accept" header)
|
126 |
+
Header append Vary Accept env=WEBPACCEPT
|
127 |
+
</IfModule>
|
128 |
+
|
129 |
+
AddType image/webp .webp
|
130 |
+
```
|
131 |
+
|
132 |
+
## Forward the querystring
|
133 |
+
By forwarding the query string, you can allow control directly from the URL. You could for example make it possible to add "?debug" to an image URL, and thereby getting a conversion report. Or make "?reconvert" force reconversion.
|
134 |
+
|
135 |
+
In order to forward the query string, you need to add this condition before the RewriteRule that redirects to *webp-on-demand.php*:
|
136 |
+
```
|
137 |
+
RewriteCond %{QUERY_STRING} (.*)
|
138 |
+
```
|
139 |
+
That condition will always be met. The side effect is that it stores the match (the complete querystring). That match will be available as %1 in the RewriteRule. So, in the RewriteRule, we will have to add "&%1" after the last argument. Here is a complete solution:
|
140 |
+
```
|
141 |
+
<IfModule mod_rewrite.c>
|
142 |
+
RewriteEngine On
|
143 |
+
|
144 |
+
# Redirect images to webp-on-demand.php (if browser supports webp)
|
145 |
+
RewriteCond %{HTTP_ACCEPT} image/webp
|
146 |
+
RewriteCond %{QUERY_STRING} (.*)
|
147 |
+
RewriteRule ^(.*)\.(jpe?g|png)$ webp-on-demand.php?source=%{SCRIPT_FILENAME}&%1 [NC,L]
|
148 |
+
</IfModule>
|
149 |
+
|
150 |
+
AddType image/webp .webp
|
151 |
+
```
|
152 |
+
|
153 |
+
Of course, in order to *do* something with that querystring, you must use them in your *webp-on-demand.php* script. You could for example use them directly in the options array sent to the *convertAndServe()* method. To achieve the mentioned "debug" and "reconvert" features, do this:
|
154 |
+
```php
|
155 |
+
$options = [
|
156 |
+
'show-report' => isset($_GET['debug']),
|
157 |
+
'reconvert' => isset($_GET['reconvert']),
|
158 |
+
'serve-original' => isset($_GET['original']),
|
159 |
+
];
|
160 |
+
```
|
161 |
+
|
162 |
+
*EDIT:*
|
163 |
+
I have just discovered a simpler way to achieve the querystring forward: The [QSA flag](https://httpd.apache.org/docs/trunk/rewrite/flags.html).
|
164 |
+
So, simply set the QSA flag in the RewriteRule, and nothing more:
|
165 |
+
```
|
166 |
+
RewriteRule ^(.*)\.(jpe?g|png)$ webp-on-demand.php?source=%{SCRIPT_FILENAME} [NC,QSA,L]
|
167 |
+
```
|
vendor/rosell-dk/webp-convert/docs/v1.3/webp-on-demand/webp-on-demand.md
ADDED
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# WebP on demand
|
2 |
+
|
3 |
+
This is a solution for automatically serving WebP images instead of jpeg/pngs [for browsers that supports WebP](https://caniuse.com/#feat=webp) (At the time of writing, 78% of all mobile users and 72% of all desktop users uses browsers supporting webp)
|
4 |
+
|
5 |
+
Once set up, it will automatically convert images, no matter how they are referenced. It for example also works on images referenced in CSS. As the solution does not require any change in the HTML, it can easily be integrated into any website / framework
|
6 |
+
|
7 |
+
## Overview
|
8 |
+
|
9 |
+
A setup consists of a PHP script that serves converted images and some *redirect rules* that redirects JPG/PNG images to the script.
|
10 |
+
|
11 |
+
|
12 |
+
## Requirements
|
13 |
+
|
14 |
+
* *Apache* or *LiteSpeed* web server. Can be made to work with *NGINX* as well. Documentation is on the roadmap.
|
15 |
+
* *mod_rewrite* module for Apache
|
16 |
+
* PHP >= 5.6 (we are only testing down to 5.6. It should however work in 5.5 as well)
|
17 |
+
* That one of the *webp-convert* converters are working (these have different requirements)
|
18 |
+
|
19 |
+
## Installation
|
20 |
+
|
21 |
+
Here we assume you are using Composer. [Not using composer? - Follow me!](https://github.com/rosell-dk/webp-convert/blob/master/docs/v1.3/webp-on-demand/without-composer.md)
|
22 |
+
|
23 |
+
### 1. Require the webp-convert library with composer
|
24 |
+
```
|
25 |
+
composer require rosell-dk/webp-convert
|
26 |
+
```
|
27 |
+
|
28 |
+
|
29 |
+
### 2. Create the script
|
30 |
+
|
31 |
+
Create a file *webp-on-demand.php*, and place it in webroot, or where-ever you like in you web-application.
|
32 |
+
|
33 |
+
Here is a minimal example to get started with:
|
34 |
+
|
35 |
+
```php
|
36 |
+
<?php
|
37 |
+
require 'vendor/autoload.php'; // Make sure to point this correctly
|
38 |
+
|
39 |
+
use WebPConvert\WebPConvert;
|
40 |
+
|
41 |
+
$source = $_GET['source']; // Absolute file path to source file. Comes from the .htaccess
|
42 |
+
$destination = $source . '.webp'; // Store the converted images besides the original images (other options are available!)
|
43 |
+
|
44 |
+
$options = [
|
45 |
+
|
46 |
+
// UNCOMMENT NEXT LINE, WHEN YOU ARE UP AND RUNNING!
|
47 |
+
'show-report' => true // Show a conversion report instead of serving the converted image.
|
48 |
+
|
49 |
+
// More options available!
|
50 |
+
];
|
51 |
+
WebPConvert::convertAndServe($source, $destination, $options);
|
52 |
+
```
|
53 |
+
|
54 |
+
### 3. Add redirect rules
|
55 |
+
Place the following rewrite rules in a *.htaccess* file in the directory where you want the solution to take effect:
|
56 |
+
|
57 |
+
```
|
58 |
+
<IfModule mod_rewrite.c>
|
59 |
+
RewriteEngine On
|
60 |
+
|
61 |
+
# Redirect images to webp-on-demand.php (if browser supports webp)
|
62 |
+
RewriteCond %{HTTP_ACCEPT} image/webp
|
63 |
+
RewriteCond %{REQUEST_FILENAME} -f
|
64 |
+
RewriteRule ^(.*)\.(jpe?g|png)$ webp-on-demand.php?source=%{SCRIPT_FILENAME} [NC,L]
|
65 |
+
</IfModule>
|
66 |
+
|
67 |
+
AddType image/webp .webp
|
68 |
+
```
|
69 |
+
If you have placed *webp-on-demand.php* in a subfolder, you will need to change the rewrite rule accordingly.
|
70 |
+
|
71 |
+
The `RewriteCond %{REQUEST_FILENAME} -f` is not strictly necessary, but there to be sure that we got an existing file, and it could perhaps also prevent some undiscovered way of misuse.
|
72 |
+
|
73 |
+
### 4. Validate that it works
|
74 |
+
|
75 |
+
Browse to a JPEG image. Instead of an image, you should see a conversion report. Hopefully, you get a success. Otherwise, you need to hook up to a cloud converter or try to meet the requirements for cwebp, gd or imagick.
|
76 |
+
|
77 |
+
Once you get a successful conversion, you can uncomment the "show-report" option in the script.
|
78 |
+
|
79 |
+
It should work now, but to be absolute sure:
|
80 |
+
|
81 |
+
- Visit a page on your site with an image on it, using *Google Chrome*.
|
82 |
+
- Right-click the page and choose "Inspect"
|
83 |
+
- Click the "Network" tab
|
84 |
+
- Reload the page
|
85 |
+
- Find a jpeg or png image in the list. In the "type" column, it should say "webp". There should also be a *X-WebP-Convert-Status* header on the image that provides some insights on how things went.
|
86 |
+
|
87 |
+
|
88 |
+
### 5. Try this improvement and see if it works
|
89 |
+
|
90 |
+
It seems that it is not necessary to pass the filename in the query string.
|
91 |
+
|
92 |
+
Try replacing `$source = $_GET['source'];` in the script with the following:
|
93 |
+
|
94 |
+
```php
|
95 |
+
$docRoot = rtrim($_SERVER["DOCUMENT_ROOT"], '/');
|
96 |
+
$requestUriNoQS = explode('?', $_SERVER['REQUEST_URI'])[0];
|
97 |
+
$source = $docRoot . urldecode($requestUriNoQS);
|
98 |
+
```
|
99 |
+
|
100 |
+
And you can then remove `?source=%{SCRIPT_FILENAME}` from the `.htaccess` file.
|
101 |
+
|
102 |
+
There are some benefits of not passing in query string:
|
103 |
+
1. Passing a path in the query string may be blocked by a firewall, as it looks suspicious.
|
104 |
+
2. The script called to convert arbitrary files
|
105 |
+
3. One person experienced problems with spaces in filenames passed in the query string. See [this issue](https://github.com/rosell-dk/webp-convert/issues/95)
|
106 |
+
|
107 |
+
|
108 |
+
### 6. Customizing and tweaking
|
109 |
+
|
110 |
+
Basic customizing is done by setting options in the `$options` array. Check out the [docs on convert()](https://github.com/rosell-dk/webp-convert/blob/master/docs/v1.3/converting/convert.md) and the [docs on convertAndServe()](https://github.com/rosell-dk/webp-convert/blob/master/docs/v1.3/serving/convert-and-serve.md)
|
111 |
+
|
112 |
+
Other tweaking is described in *docs/webp-on-demand/tweaks.md*:
|
113 |
+
- [Store converted images in separate folder](https://github.com/rosell-dk/webp-convert/blob/master/docs/v1.3/webp-on-demand/tweaks.md#store-converted-images-in-separate-folder)
|
114 |
+
- [CDN](https://github.com/rosell-dk/webp-convert/blob/master/docs/v1.3/webp-on-demand/tweaks.md#cdn)
|
115 |
+
- [Make .htaccess route directly to existing images](https://github.com/rosell-dk/webp-convert/blob/master/docs/v1.3/webp-on-demand/tweaks.md#make-htaccess-route-directly-to-existing-images)
|
116 |
+
- [Forward the query string](https://github.com/rosell-dk/webp-convert/blob/master/docs/v1.3/webp-on-demand/tweaks.md#forward-the-querystring)
|
117 |
+
|
118 |
+
|
119 |
+
## Troubleshooting
|
120 |
+
|
121 |
+
### The redirect rule doesn't seem to be working
|
122 |
+
If images are neither routed to the converter or a 404, it means that the redirect rule isn't taking effect. Common reasons for this includes:
|
123 |
+
|
124 |
+
- Perhaps there are other rules in your *.htaccess* that interfere with the rules?
|
125 |
+
- Perhaps your site is on *Apache*, but it has been configured to use *Nginx* to serve image files. To find out which server that is handling the images, browse to an image and eximine the "Server" response header. In case *NGINX* are serving images, see if you can reconfigure your server setup. Alternatively, you can create *NGINX* rewrite rules. There are some [here](https://github.com/S1SYPHOS/kirby-webp#nginx) and [there](https://github.com/uhop/grunt-tight-sprite/wiki/Recipe:-serve-WebP-with-nginx-conditionally).
|
126 |
+
- Perhaps the server isn't configured to allow *.htaccess* files? Try inserting rubbish in the top of the *.htaccess* file and refresh. You should now see an *Internal Server Error* error page. If you don't, your *.htaccess* file is ignored. Probably you will need to set *AllowOverride All* in your Virtual Host. [Look here for more help](
|
127 |
+
https://docs.bolt.cm/3.4/howto/making-sure-htaccess-works#test-if-htaccess-is-working)
|
128 |
+
- Perhaps the Apache *mod_rewrite* extension isn't enabled? Try removing both `<IfModule mod_rewrite.c>` and `</IfModule>` lines: if you get an *Internal Server Error* error page after this change, it's probably that it's indeed not enabled.
|
129 |
+
|
130 |
+
|
131 |
+
## Related
|
132 |
+
* https://www.maxcdn.com/blog/how-to-reduce-image-size-with-webp-automagically/
|
133 |
+
* https://www.digitalocean.com/community/tutorials/how-to-create-and-serve-webp-images-to-speed-up-your-website
|
vendor/rosell-dk/webp-convert/docs/v1.3/webp-on-demand/without-composer.md
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# WebP On Demand without composer
|
2 |
+
|
3 |
+
For your convenience, the library has been cooked down to two files: *webp-on-demand-1.inc* and *webp-on-demand-2.inc*. The second one is loaded when the first one decides it needs to do a conversion (and not simply serve existing image).
|
4 |
+
|
5 |
+
## Installing
|
6 |
+
|
7 |
+
### 1. Copy the latest build files into your website
|
8 |
+
Copy *webp-on-demand-1.inc* and *webp-on-demand-2.inc* from the *build* folder into your website (in 2.0, they are located in "src-build"). They can be located wherever you like.
|
9 |
+
|
10 |
+
### 2. Create a *webp-on-demand.php*
|
11 |
+
|
12 |
+
Create a file *webp-on-demand.php*, and place it in webroot, or where-ever you like in you web-application.
|
13 |
+
|
14 |
+
Here is a minimal example to get started with. Note that this example only works in version 1.x. In 2.0, the `require-for-conversion` option has been removed, so the [procedure is different](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/webp-on-demand/without-composer.md).
|
15 |
+
|
16 |
+
```php
|
17 |
+
<?php
|
18 |
+
// To start with, lets display any errors.
|
19 |
+
// You can later comment these out
|
20 |
+
error_reporting(E_ALL);
|
21 |
+
ini_set("display_errors", 1);
|
22 |
+
|
23 |
+
require 'webp-on-demand-1.inc';
|
24 |
+
|
25 |
+
use WebPConvert\WebPConvert;
|
26 |
+
|
27 |
+
$source = $_GET['source']; // Absolute file path to source file. Comes from the .htaccess
|
28 |
+
$destination = $source . '.webp'; // Store the converted images besides the original images (other options are available!)
|
29 |
+
|
30 |
+
$options = [
|
31 |
+
|
32 |
+
// Tell where to find the webp-convert-and-serve library, which will
|
33 |
+
// be dynamically loaded, if need be.
|
34 |
+
'require-for-conversion' => 'webp-on-demand-2.inc',
|
35 |
+
|
36 |
+
// UNCOMMENT NEXT LINE, WHEN YOU ARE UP AND RUNNING!
|
37 |
+
'show-report' => true // Show a conversion report instead of serving the converted image.
|
38 |
+
|
39 |
+
// More options available!
|
40 |
+
];
|
41 |
+
WebPConvert::convertAndServe($source, $destination, $options);
|
42 |
+
```
|
43 |
+
|
44 |
+
### 3. Continue the main install instructions from step 3
|
45 |
+
[Click here to continue...](https://github.com/rosell-dk/webp-on-demand#3-add-redirect-rules)
|
vendor/rosell-dk/webp-convert/docs/v2.0/converting/architecture-q50-w600.jpg
ADDED
Binary file
|
vendor/rosell-dk/webp-convert/docs/v2.0/converting/converters/stack.md
ADDED
@@ -0,0 +1,248 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Stack converter
|
2 |
+
|
3 |
+
The stack converter is a mechanism for trying all available converters until success. Well, the default is to try all converters, but this can be configured.
|
4 |
+
|
5 |
+
When calling `WebPConvert::convert($source, $destination, $options);`, you are actually invoking the stack converter.
|
6 |
+
|
7 |
+
## Passing options down to the individual converters
|
8 |
+
|
9 |
+
Any option that you pass to the Stack converter will be passed on to the individual converters. For example, setting options to the following will set the metadata option on all converters:
|
10 |
+
|
11 |
+
```php
|
12 |
+
$options = [
|
13 |
+
'metadata' => 'all',
|
14 |
+
];
|
15 |
+
```
|
16 |
+
|
17 |
+
If you need the option to be different for a single converter there are several ways to do it:
|
18 |
+
|
19 |
+
#### 1. Prefixing
|
20 |
+
|
21 |
+
Options prefixed with a converter id are only effective for that converter, and overrides the non-prefixed option.
|
22 |
+
|
23 |
+
Ie, the following will set "metadata" to "all" for all converters, except *cwebp*, where "metadata" is set to "exif"
|
24 |
+
|
25 |
+
```php
|
26 |
+
$options = [
|
27 |
+
'metadata' => 'all',
|
28 |
+
'cwebp-metadata' => 'exif'
|
29 |
+
];
|
30 |
+
```
|
31 |
+
|
32 |
+
Prefixing is by the way a general feature in the way options are handled and thus not confined to the stack converter. (though it admittedly only finds its use in the context of a stack converter).
|
33 |
+
|
34 |
+
|
35 |
+
#### 2. Using the `converter-options` option
|
36 |
+
The *converter-options* option is convenient for setting a whole bunch of converter-specific options in one go.
|
37 |
+
|
38 |
+
Example:
|
39 |
+
```php
|
40 |
+
$options = [
|
41 |
+
'converter-options' => [
|
42 |
+
'wpc' => [
|
43 |
+
'crypt-api-key-in-transfer' => true
|
44 |
+
'api-key' => 'my dog is white',
|
45 |
+
'api-url' => 'https://example.com/wpc.php',
|
46 |
+
'api-version' => 1,
|
47 |
+
],
|
48 |
+
],
|
49 |
+
]
|
50 |
+
```
|
51 |
+
|
52 |
+
#### 3. As part of the `converters` option
|
53 |
+
This option is explained further down this document.
|
54 |
+
|
55 |
+
|
56 |
+
## Modifying the stack
|
57 |
+
|
58 |
+
The default stack consists of the following converters:
|
59 |
+
- cwebp
|
60 |
+
- vips
|
61 |
+
- imagick
|
62 |
+
- gmagick
|
63 |
+
- imagemagick
|
64 |
+
- graphicsmagick
|
65 |
+
- wpc
|
66 |
+
- ewww
|
67 |
+
- gd
|
68 |
+
|
69 |
+
The order has carefully been chosen based on the capabilities of the converters. It is a rank, if you will.
|
70 |
+
|
71 |
+
Now, say that on your system, you only have *gd* working. With the default stack, this means that eight converters will be tested for operationality before getting to *gd* – each time a conversion is made. You might be tempted to optimizing the flow by putting *gd* on the top. *I would generally advise against this* for the following reasons:
|
72 |
+
|
73 |
+
1. It might be that one of the other (and better) converters starts working without you noticing. You will then miss out.
|
74 |
+
2. All converters have all been designed to exit very quickly when they are not operational. It only takes a few milliseconds for the library to detect that a converter is not operational - literally. For example, if no api key is provided for ewww, it will exit immediately.
|
75 |
+
|
76 |
+
However, there are valid reasons to modify the stack. For example, you may prefer *vips* over *cwebp*, or you may wish to remove a converter completely due to problems with that converter on your platform.
|
77 |
+
|
78 |
+
### Changing the order of the converters
|
79 |
+
To change the order, you can use the `preferred-converters` option. With this option you move selected converters to the top of the stack.
|
80 |
+
|
81 |
+
So, if you want the stack to start with *vips* and then *ewww*, but keep the rest of the order, you can set the following:
|
82 |
+
|
83 |
+
```php
|
84 |
+
$options[
|
85 |
+
'preferred-converters' => ['vips', 'ewww'];
|
86 |
+
];
|
87 |
+
```
|
88 |
+
|
89 |
+
### Removing converters from the stack
|
90 |
+
To remove converters, you can use the `skip` option and prefixing. For example, to remove *cwebp* and *gd*:
|
91 |
+
|
92 |
+
```php
|
93 |
+
$options = [
|
94 |
+
'ewww-skip' => true,
|
95 |
+
'cwebp-skip' => true,
|
96 |
+
];
|
97 |
+
```
|
98 |
+
|
99 |
+
### Adding converters to the stack
|
100 |
+
If you are using a custom converter, you can add it to the stack like this:
|
101 |
+
|
102 |
+
```php
|
103 |
+
$options = [
|
104 |
+
'extra-converters' => [
|
105 |
+
'\\MyNameSpace\\WonderConverter'
|
106 |
+
],
|
107 |
+
];
|
108 |
+
```
|
109 |
+
|
110 |
+
It will be added to the bottom of the stack. To place it differently, use the `preferred-converters` option and set it to ie `'preferred-converters' => ['vips','\\MyNameSpace\\WonderConverter']`
|
111 |
+
|
112 |
+
|
113 |
+
Here is an example which adds an extra ewww converter. This way you can have a backup api-key in case the quota of the first has been exceeded.
|
114 |
+
|
115 |
+
```
|
116 |
+
$options = [
|
117 |
+
'extra-converters' => [
|
118 |
+
[
|
119 |
+
'converter' => 'ewww',
|
120 |
+
'options' => [
|
121 |
+
'api-key' => 'provide-backup-key-here',
|
122 |
+
]
|
123 |
+
]
|
124 |
+
]
|
125 |
+
];
|
126 |
+
```
|
127 |
+
Note however that you will not be able to reorder that new ewww converter using `preferred-converters`, as there are now two converters with id=ewww, and that option has not been designed for that. Instead, you can add a sub-stack of ewww converters - see the "Stacking" section below.
|
128 |
+
|
129 |
+
|
130 |
+
### Setting the converter array explicitly
|
131 |
+
Using the `converters` option, you can set the converter array explicitly. What differentiates this from the `preferred-converters` option (besides that it completely redefines the converter ordering) is that it allows you to set both the converters *and* options for each converter in one go and that it allows a complex structure - such as a stack within a stack. Also, this structure can simplify things in some cases, such as when the options is generated by a GUI, as it is in WebP Express.
|
132 |
+
|
133 |
+
The array specifies the converters to try and their order. Each item can be:
|
134 |
+
|
135 |
+
- An id (ie "cwebp")
|
136 |
+
- A fully qualified class name (in case you have programmed your own custom converter)
|
137 |
+
- An array with two keys: "converter" and "options".
|
138 |
+
|
139 |
+
Example:
|
140 |
+
|
141 |
+
```php
|
142 |
+
$options = [
|
143 |
+
'quality' => 71,
|
144 |
+
'converters' => [
|
145 |
+
'cwebp',
|
146 |
+
[
|
147 |
+
'converter' => 'vips',
|
148 |
+
'options' => [
|
149 |
+
'quality' => 72
|
150 |
+
]
|
151 |
+
],
|
152 |
+
[
|
153 |
+
'converter' => 'ewww',
|
154 |
+
'options' => [
|
155 |
+
'quality' => 73
|
156 |
+
]
|
157 |
+
],
|
158 |
+
'wpc',
|
159 |
+
'imagemagick',
|
160 |
+
'\\MyNameSpace\\WonderConverter'
|
161 |
+
],
|
162 |
+
];
|
163 |
+
```
|
164 |
+
|
165 |
+
### Stacking
|
166 |
+
Stack converters behave just like regular converters. They ARE in fact "regular", as they extend the same base class as all converters. This means that you can have a stack within a stack. You can for example utilize this for supplying a backup api key for the ewww converter. Like this:
|
167 |
+
|
168 |
+
```php
|
169 |
+
$options = [
|
170 |
+
'ewww-skip' => true, // skip the default ewww converter (we use stack of ewww converters instead)
|
171 |
+
'extra-converters' => [
|
172 |
+
[
|
173 |
+
// stack of ewww converters
|
174 |
+
'converter' => 'stack',
|
175 |
+
'options' => [
|
176 |
+
'ewww-skip' => false, // do not skip ewww from here on
|
177 |
+
'converters' => [
|
178 |
+
[
|
179 |
+
'converter' => 'ewww',
|
180 |
+
'options' => [
|
181 |
+
'api-key' => 'provide-preferred-key-here',
|
182 |
+
]
|
183 |
+
],
|
184 |
+
[
|
185 |
+
'converter' => 'ewww',
|
186 |
+
'options' => [
|
187 |
+
'api-key' => 'provide-backup-key-here',
|
188 |
+
]
|
189 |
+
]
|
190 |
+
],
|
191 |
+
]
|
192 |
+
]
|
193 |
+
],
|
194 |
+
'preferred-converters' => ['cwebp', 'vips', 'stack'], // set our stack of ewww converters third in queue
|
195 |
+
];
|
196 |
+
```
|
197 |
+
Note that we set `ewww-skip` in order to disable the *ewww* converter which is part of the defaults. As options are inherited, we have to reset this option again. These steps are not necessary when using the `converters` option.
|
198 |
+
|
199 |
+
Also note that the options for modifying the converters (`converters`, `extra-converters`, `converter-options`) does not get passed down.
|
200 |
+
|
201 |
+
Also note that if you want to add two stacks with `extra-converters`, the `preferred-converters` option will not work, as there are two converters called "stack". One workaround is to add those two stacks to their own stack, so you have three levels. Or you can of course simply use the `converters` option to get complete control.
|
202 |
+
|
203 |
+
|
204 |
+
### Shuffling
|
205 |
+
|
206 |
+
The stack can be configured to shuffling, meaning that the the order will be random. This can for example be used to balance load between several wpc instances in a sub stack.
|
207 |
+
|
208 |
+
Shuffling is enabled with the `shuffle` option.
|
209 |
+
|
210 |
+
Here is an example of balancing load between several *wpc* instances:
|
211 |
+
|
212 |
+
```php
|
213 |
+
$options = [
|
214 |
+
'wpc-skip' => true, // skip the default wpc converter (we use stack of wpc converters instead)
|
215 |
+
'extra-converters' => [
|
216 |
+
[
|
217 |
+
// stack of wpc converters
|
218 |
+
'converter' => 'stack',
|
219 |
+
'options' => [
|
220 |
+
'wpc-skip' => false, // do not skip wpc from here on
|
221 |
+
'shuffle' => true,
|
222 |
+
|
223 |
+
'converters' => [
|
224 |
+
[
|
225 |
+
'converter' => 'wpc',
|
226 |
+
'options' => [
|
227 |
+
'api-key' => 'my-dog',
|
228 |
+
'api-url' => 'my-wpc.com/wpc.php',
|
229 |
+
'api-version' => 1,
|
230 |
+
'crypt-api-key-in-transfer' => true,
|
231 |
+
]
|
232 |
+
],
|
233 |
+
[
|
234 |
+
'converter' => 'wpc',
|
235 |
+
'options' => [
|
236 |
+
'api-key' => 'my-other-dog',
|
237 |
+
'api-url' => 'my-other-wpc.com/wpc.php',
|
238 |
+
'api-version' => 1,
|
239 |
+
'crypt-api-key-in-transfer' => true,
|
240 |
+
]
|
241 |
+
]
|
242 |
+
],
|
243 |
+
]
|
244 |
+
]
|
245 |
+
],
|
246 |
+
'preferred-converters' => ['cwebp', 'vips', 'stack'], // set our stack of wpc converters third in queue
|
247 |
+
];
|
248 |
+
```
|
vendor/rosell-dk/webp-convert/docs/v2.0/converting/dice.png
ADDED
Binary file
|
vendor/rosell-dk/webp-convert/docs/v2.0/converting/introduction-for-converting.md
ADDED
@@ -0,0 +1,218 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Introduction to converting with WebPConvert
|
2 |
+
|
3 |
+
**NOTE: This document only applies to the upcoming 2.0 version**
|
4 |
+
|
5 |
+
The library is able to convert images to webp using a variety of methods (*gd*, *imagick*, *vips* etc.), which we call "converters". A converter is called like this:
|
6 |
+
|
7 |
+
```php
|
8 |
+
use WebPConvert\Convert\Converters\Gd;
|
9 |
+
|
10 |
+
Gd::convert($source, $destination, $options=[], $logger=null);
|
11 |
+
```
|
12 |
+
|
13 |
+
All converters comes with requirements. For example, the *Gd* converter requires that Gd is installed and compiled with webp support. The cloud converters requires an api key. In case the conversion fails, an exception is thrown.
|
14 |
+
|
15 |
+
## Insights to the process
|
16 |
+
If *$logger* is supplied, the converter will log the details of how the conversion process went to that logger. You can for example use the supplied *EchoLogger* to print directly to screen or the *BufferLogger* to collect the log entries. Here is a simple example which prints the process to screen:
|
17 |
+
|
18 |
+
```php
|
19 |
+
use WebPConvert\Convert\Converters\Gd;
|
20 |
+
use WebPConvert\Loggers\EchoLogger;
|
21 |
+
|
22 |
+
Gd::convert($source, $destination, $options=[], new EchoLogger());
|
23 |
+
```
|
24 |
+
|
25 |
+
It will output something like this:
|
26 |
+
|
27 |
+
```text
|
28 |
+
GD Version: 2.2.5
|
29 |
+
image is true color
|
30 |
+
Quality set to same as source: 61
|
31 |
+
|
32 |
+
Converted image in 20 ms, reducing file size with 34% (went from 12 kb to 8 kb)
|
33 |
+
```
|
34 |
+
|
35 |
+
## The stack converter
|
36 |
+
When your software is going to be installed on a variety of systems which you do not control, you can try the converters one at the time until success. The converters has been designed to exit quickly when system requirements are not met. To make this task easy, a *Stack* converter has been created.
|
37 |
+
|
38 |
+
The stack converter has two special options:
|
39 |
+
|
40 |
+
| option | description |
|
41 |
+
| ------------------------- | ----------- |
|
42 |
+
| converters (array) | Converters to try (ids or class names, in case you have your own custom converter) |
|
43 |
+
| converter-options (array) | Extra options for specific converters. |
|
44 |
+
|
45 |
+
Alternatively to the converter-options array, you can simply prefix options with the converter id.
|
46 |
+
|
47 |
+
I recommend leave the converters array at the default unless you have strong reasons not to. Otherwise you might miss out when new converters are added.
|
48 |
+
|
49 |
+
### Example:
|
50 |
+
|
51 |
+
```php
|
52 |
+
<?php
|
53 |
+
use WebPConvert\Convert\Converters\Stack;
|
54 |
+
|
55 |
+
Stack::convert($source, $destination, $options = [
|
56 |
+
|
57 |
+
// PS: only set converters if you have strong reasons to do so
|
58 |
+
'converters' => [
|
59 |
+
'cwebp', 'vips', 'imagick', 'gmagick', 'imagemagick', 'graphicsmagick', 'wpc', 'ewww', 'gd'
|
60 |
+
],
|
61 |
+
|
62 |
+
// Any available options can be set here, they dribble down to all converters.
|
63 |
+
'metadata' => 'all',
|
64 |
+
|
65 |
+
// To override for specific converter, you can prefix with converter id:
|
66 |
+
'cwebp-metadata' => 'exif',
|
67 |
+
|
68 |
+
// This can for example be used for setting ewww api key:
|
69 |
+
'ewww-api-key' => 'your-ewww-api-key-here',
|
70 |
+
|
71 |
+
// As an alternative to prefixing, you can use "converter-options" to set a whole bunch of overrides in one go:
|
72 |
+
'converter-options' => [
|
73 |
+
'wpc' => [
|
74 |
+
'crypt-api-key-in-transfer' => true
|
75 |
+
'api-key' => 'my dog is white',
|
76 |
+
'api-url' => 'https://example.com/wpc.php',
|
77 |
+
'api-version' => 1,
|
78 |
+
],
|
79 |
+
],
|
80 |
+
], $logger=null);
|
81 |
+
```
|
82 |
+
|
83 |
+
Note: As an alternative to setting the third party credentials in the options, you can set them through constants or environment variables ("WEBPCONVERT_EWWW_API_KEY", "WEBPCONVERT_WPC_API_KEY", "WEBPCONVERT_WPC_API_URL"). Paths to binaries can also be set like that (it is rarely needed to do this): "WEBPCONVERT_CWEBP_PATH", "WEBPCONVERT_GRAPHICSMAGICK_PATH" and WEBPCONVERT_IMAGEMAGICK_PATH"
|
84 |
+
|
85 |
+
To set an environment variable in Apache, you can add a line like this in your `.htaccess` or vhost configuration:
|
86 |
+
```
|
87 |
+
# Set ewww api key for WebP Convert
|
88 |
+
SetEnv WEBPCONVERT_EWWW_API_KEY yourVerySecretApiKeyGoesHere
|
89 |
+
|
90 |
+
# Set custom path to imagick for WebP Convert
|
91 |
+
SetEnv WEBPCONVERT_IMAGEMAGICK_PATH /usr/local/bin/magick
|
92 |
+
```
|
93 |
+
To set a constant:
|
94 |
+
```php
|
95 |
+
define('WEBPCONVERT_IMAGEMAGICK_PATH', '/usr/local/bin/magick');
|
96 |
+
```
|
97 |
+
|
98 |
+
|
99 |
+
## Configuring the options
|
100 |
+
|
101 |
+
### Auto quality
|
102 |
+
**Q:** What do you get if you convert a low quality jpeg (ie q=50) into a high quality webp (ie q=90) ?\
|
103 |
+
**A:** You maintain the low quality, but you get a large file`
|
104 |
+
|
105 |
+
What should we have done instead? We should have converted with a quality around 50. Of course, quality is still low - we cannot fix that - but it will not be less, *and the converted file will be much smaller*.
|
106 |
+
|
107 |
+
As unnecessary large conversions are rarely desirable, this library per default converts jpeg files with the same quality level as the source. This functionality requires that either *imagemagick*, *graphicsmagick* or *imagick* is installed (not necessarily compiled with webp support). When they are, all converters will have the "auto" quality functionality. The *wpc* cloud converter supports auto quality if these are installed on the server that *wpc* is installed on.
|
108 |
+
|
109 |
+
How much can be gained? A lot!
|
110 |
+
The following low quality (q=50) jpeg weighs 54 kb. If this is converted to webp with quality=80, the size of the converted file is 52kb - almost no reduction! With auto, the quality of the webp will be set to 50, and the size will be 34kb. Visually, the results are indistinguable.
|
111 |
+
|
112 |
+
![A low quality jpeg](https://raw.githubusercontent.com/rosell-dk/webp-convert/master/docs/v2.0/converting/architecture-q50-w600.jpg)
|
113 |
+
|
114 |
+
**Q:** What do you get if you convert an excessively high quality jpeg into an excessively high quality webp?\
|
115 |
+
**A:** An excessively big file
|
116 |
+
|
117 |
+
The size of a webp file grows enormously with the quality setting. For the web however, a quality above 80 is rarely needed. For this reason the library has a per default limits the quality to the value of the *max-quality* option (default: 85).
|
118 |
+
|
119 |
+
In case quality detection is unavailable, the quality gets the value of the *default-quality* option (default is 70 for JPEGs and 85 for PNGs).
|
120 |
+
|
121 |
+
So, how much can be gained? A lot!
|
122 |
+
The following excessively high quality jpeg (q=100) weighs 146 kb. Converting it to webp with q=100 results in a 99kb image (this would happen if we had the auto feature, but not the max-quality feature). Converting it to q=85 results in a 40kb image.
|
123 |
+
|
124 |
+
![A (too) high quality jpeg](https://raw.githubusercontent.com/rosell-dk/webp-convert/master/docs/v2.0/converting/mouse-q100.jpg)
|
125 |
+
|
126 |
+
|
127 |
+
### Auto selecting between lossless/lossy encoding
|
128 |
+
WebP files can be encoded using either *lossless* or *lossy* encoding. The JPEG format is lossy and the PNG is lossless. However, this does not mean that you necessarily get the best conversion by always encoding JPEG to lossy and PNG to lossless. With JPEGs it is often the case, as they are usually pictures and pictures usually best encoded as lossy. With PNG it is however a different story, as you often can get a better compression using lossy encoding, also when using high quality level of say 85, which should be enough for the web.
|
129 |
+
|
130 |
+
As unnecessary large conversions are rarely desirable, this library per default tries to convert images using both lossy and lossless encoding and automatically selects the smallest. This is controlled using the *encoding* option, which per default is "auto", but can also be set to "lossy" or "lossless".
|
131 |
+
|
132 |
+
As an example, the following PNG (231 kb) will be compressed to 156 kb when converting to *lossless* webp. But when converting to *lossy* (quality: 85), it is compressed to merely 68 kb - less than half. (in case you are confused about the combination of lossy and transparency: Yes, you can have both at the same time with webp).
|
133 |
+
|
134 |
+
![Dice](https://raw.githubusercontent.com/rosell-dk/webp-convert/master/docs/v2.0/converting/dice.png)
|
135 |
+
|
136 |
+
Unless you changed the `near-lossless` option described below, the choice is actually between lossy and *near-lossless*.
|
137 |
+
|
138 |
+
Note that *gd* and *ewww* doesn't support this feature. *gd* can only produce lossy, and will simply do that. *ewww* can not be configured to use a certain encoding, but automatically chooses *lossless* encoding for PNGs and lossy for JPEGs.
|
139 |
+
|
140 |
+
### Near-lossless
|
141 |
+
*cwebp* and *vips* supports "near-lossless" mode. Near lossless produces a webp with lossless encoding but adjusts pixel values to help compressibility. The result is a smaller file. The price is described as a minimal impact on the visual quality.
|
142 |
+
|
143 |
+
As unnecessary large conversions are rarely desirable, this library per default sets *near-lossless* to 60. To disable near-lossless, set it to 100.
|
144 |
+
|
145 |
+
When compressing the image above (231 kb) to lossless, it compressed to 156 kb when near-lossless is set to 100. Setting near-lossless to 60 gets the size down to 110 kb while still looking great.
|
146 |
+
|
147 |
+
You can read more about the near-lossless mode [here](https://groups.google.com/a/webmproject.org/forum/#!topic/webp-discuss/0GmxDmlexek)
|
148 |
+
|
149 |
+
### Alpha-quality
|
150 |
+
All converters, except *gd* and *ewww* supports "alpha-quality" option. This allows lossy compressing of the alpha channel.
|
151 |
+
|
152 |
+
As unnecessary large conversions are rarely desirable, this library per default sets *alpha-quality* to 85. Set it to 100 to achieve lossless compression of alhpa.
|
153 |
+
|
154 |
+
Btw, the image above gets compressed to 68 kb with alpha quality set to 100. Surprisingly, it gets slightly larger (70 kb) with alpha quality set to 85. Setting alpha quality to 50 gets it down to merely 35 kb - about half - while still looking great.
|
155 |
+
|
156 |
+
You can read more about the alpha-quality option [here](https://developers.google.com/speed/webp/docs/cwebp)
|
157 |
+
|
158 |
+
|
159 |
+
### PNG og JPEG-specific options.
|
160 |
+
|
161 |
+
To have options depending on the image type of the source, you can use the `png` and `jpeg` keys.
|
162 |
+
|
163 |
+
The following options mimics the default behaviour:
|
164 |
+
|
165 |
+
```php
|
166 |
+
$options = [
|
167 |
+
'png' => [
|
168 |
+
'encoding' => 'auto', /* Try both lossy and lossless and pick smallest */
|
169 |
+
'near-lossless' => 60, /* The level of near-lossless image preprocessing (when trying lossless) */
|
170 |
+
'quality' => 85, /* Quality when trying lossy. It is set high because pngs is often selected to ensure high quality */
|
171 |
+
],
|
172 |
+
'jpeg' => [
|
173 |
+
'encoding' => 'auto', /* If you are worried about the longer conversion time, you could set it to "lossy" instead (lossy will often be smaller than lossless for jpegs) */
|
174 |
+
'quality' => 'auto', /* Set to same as jpeg (requires imagick or gmagick extension, not necessarily compiled with webp) */
|
175 |
+
'max-quality' => 80, /* Only relevant if quality is set to "auto" */
|
176 |
+
'default-quality' => 75, /* Fallback quality if quality detection isnt working */
|
177 |
+
]
|
178 |
+
];
|
179 |
+
```
|
180 |
+
|
181 |
+
You can use it for any option, also the converter specific options.
|
182 |
+
A use case could for example be to use different converters for png and jpeg:
|
183 |
+
|
184 |
+
```php
|
185 |
+
$options = [
|
186 |
+
'png' => [
|
187 |
+
'converters' => ['ewww'],
|
188 |
+
],
|
189 |
+
'jpeg' => [
|
190 |
+
'converters' => ['gd'],
|
191 |
+
]
|
192 |
+
];
|
193 |
+
```
|
194 |
+
|
195 |
+
## Available options
|
196 |
+
|
197 |
+
**All** available options are documented [here](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md).
|
198 |
+
|
199 |
+
Here is a quick overview of the few ones discussed here.
|
200 |
+
|
201 |
+
| Option | Default (jpeg) | Default (png) | Description |
|
202 |
+
| ----------------- | ------------------ | ------------------- | ---------------------------------------------------------------------------------- |
|
203 |
+
| quality | "auto" | 85 | See the "Auto quality" section above. |
|
204 |
+
| max-quality | 85 | 85 | Only relevant for jpegs and when quality is set to "auto". |
|
205 |
+
| default-quality | 75 | 85 | |
|
206 |
+
| metadata | "none" | "none" | Valid values: "all", "none", "exif", "icc", "xmp".<br><br>Note: Currently only *cwebp* supports all values. *gd* will always remove all metadata. *ewww*, *imagick* and *gmagick* can either strip all, or keep all (they will keep all, unless metadata is set to *none*) |
|
207 |
+
| encoding | "auto" | "auto" | See the "Auto selecting between lossless/lossy encoding" section above |
|
208 |
+
| jpeg | - | - | Array of options which will be merged into the other options when source is a JPEG |
|
209 |
+
| png | - | - | Array of options which will be merged into the other options when source is a PNG |
|
210 |
+
| skip | false | false | If true, conversion will be skipped (ie for skipping png conversion for some converters) |
|
211 |
+
|
212 |
+
|
213 |
+
## More info
|
214 |
+
|
215 |
+
- The complete api is available [here](https://www.bitwise-it.dk/webp-convert/api/2.0/html/index.xhtml)
|
216 |
+
- The converters are described in more detail here (for 1.3.9): [docs/v1.3/converting/converters.md](https://github.com/rosell-dk/webp-convert/blob/master/docs/v1.3/converting/converters.md).
|
217 |
+
- On the github wiki you can find installation instructions for imagick with webp, gd with webp, etc.
|
218 |
+
- This document is a newly written introduction to the convert api, which has been created as part of the 2.0 release. The old introduction, which was made for 1.3 is available here: [docs/converting/v1.3/convert.md](https://github.com/rosell-dk/webp-convert/blob/master/docs/v1.3/converting/convert.md).
|
vendor/rosell-dk/webp-convert/docs/v2.0/converting/mouse-q100.jpg
ADDED
Binary file
|
vendor/rosell-dk/webp-convert/docs/v2.0/converting/options.md
ADDED
@@ -0,0 +1,346 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Options
|
2 |
+
|
3 |
+
This is a list of all options available for converting.
|
4 |
+
|
5 |
+
Note that as the *stack* and *wpc* converters delegates the options to their containing converters, the options that they supports depend upon the converters they have been configured to use (and which of them that are operational)<br><br>
|
6 |
+
|
7 |
+
### `alpha-quality`
|
8 |
+
```
|
9 |
+
Type: integer (0-100)
|
10 |
+
Default: 85
|
11 |
+
Supported by: cwebp, vips, imagick, gmagick, imagemagick and graphicsmagick
|
12 |
+
```
|
13 |
+
Quality of alpha channel. Only relevant for lossy encoding and only relevant for images with alpha channel.<br><br>
|
14 |
+
|
15 |
+
### `auto-filter`
|
16 |
+
```
|
17 |
+
Type: boolean
|
18 |
+
Default: false
|
19 |
+
Supported by: cwebp, vips, imagick, gmagick and imagemagick
|
20 |
+
```
|
21 |
+
Turns auto-filter on. This algorithm will spend additional time optimizing the filtering strength to reach a well-balanced quality. Unfortunately, it is extremely expensive in terms of computation. It takes about 5-10 times longer to do a conversion. A 1MB picture which perhaps typically takes about 2 seconds to convert, will takes about 15 seconds to convert with auto-filter. So in most cases, you will want to leave this at its default, which is off.<br><br>
|
22 |
+
|
23 |
+
### `cwebp-command-line-options`
|
24 |
+
```
|
25 |
+
Type: string
|
26 |
+
Default: ''
|
27 |
+
Supported by: cwebp
|
28 |
+
```
|
29 |
+
This allows you to set any parameter available for cwebp in the same way as you would do when executing *cwebp*. You could ie set it to "-sharpness 5 -mt -crop 10 10 40 40". Read more about all the available parameters in [the docs](https://developers.google.com/speed/webp/docs/cwebp).<br><br>
|
30 |
+
|
31 |
+
### `cwebp-rel-path-to-precompiled-binaries`
|
32 |
+
```
|
33 |
+
Type: string
|
34 |
+
Default: './Binaries'
|
35 |
+
Supported by: cwebp
|
36 |
+
```
|
37 |
+
Allows you to change where to look for the precompiled binaries. While this may look as a risk, it is completely safe, as the binaries are hash-checked before being executed. The option is needed when you are using two-file version of webp-on-demand.
|
38 |
+
|
39 |
+
### `cwebp-try-common-system-paths`
|
40 |
+
```
|
41 |
+
Type: boolean
|
42 |
+
Default: true
|
43 |
+
Supported by: cwebp
|
44 |
+
```
|
45 |
+
If set, the converter will try to look for cwebp in locations such as `/usr/bin/cwebp`. It is a limited list. It might find something that isn't found using `try-discovering-cwebp` if these common paths are not within PATH or neither `which` or `whereis` are available.
|
46 |
+
|
47 |
+
### `cwebp-try-cwebp`
|
48 |
+
```
|
49 |
+
Type: boolean
|
50 |
+
Default: true
|
51 |
+
Supported by: cwebp
|
52 |
+
```
|
53 |
+
If set, the converter will try the a plain "cwebp" command (without specifying a path).
|
54 |
+
|
55 |
+
### `try-discovering-cwebp`
|
56 |
+
```
|
57 |
+
Type: boolean
|
58 |
+
Default: true
|
59 |
+
Supported by: cwebp
|
60 |
+
```
|
61 |
+
If set, the converter will try to discover installed cwebp binaries using the `which -a cwebp` command, or in case that fails, the `whereis -b cwebp` command. These commands will find cwebp binaries residing in PATH. They might find cwebp binaries which are not found by enabling `cwebp-try-common-system-paths`
|
62 |
+
|
63 |
+
|
64 |
+
### `cwebp-try-supplied-binary-for-os`
|
65 |
+
```
|
66 |
+
Type: boolean
|
67 |
+
Default: true
|
68 |
+
Supported by: cwebp
|
69 |
+
```
|
70 |
+
If set, the converter will try the precompiled cwebp binary that are located in `src/Convert/Converters/Binaries`, for the current OS. The binaries are hash-checked before executed.
|
71 |
+
|
72 |
+
### `default-quality`
|
73 |
+
```
|
74 |
+
Type: integer (0-100)
|
75 |
+
Default: 75 for jpegs and 85 for pngs
|
76 |
+
Supported by: all (cwebp, ewww, gd, ffmpeg, gmagick, graphicsmagick, imagick, imagemagick, vips)
|
77 |
+
```
|
78 |
+
Read about this option in the ["auto quality" section in the introduction](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md#auto-quality).<br><br>
|
79 |
+
|
80 |
+
### `encoding`
|
81 |
+
```
|
82 |
+
Type: string ("lossy" | "lossless" | "auto")
|
83 |
+
Default: "auto"
|
84 |
+
Supported by: cwebp, vips, ffmpeg, imagick, gmagick, imagemagick and graphicsmagick (gd always uses lossy encoding, ewww uses lossless for pngs and lossy for jpegs)
|
85 |
+
```
|
86 |
+
Read about this option in the ["lossy/lossless" section in the introduction](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md#auto-selecting-between-losslesslossy-encoding).<br><br>
|
87 |
+
|
88 |
+
### `ewww-api-key`
|
89 |
+
```
|
90 |
+
Type: string
|
91 |
+
Default: ''
|
92 |
+
Supported by: ewww
|
93 |
+
```
|
94 |
+
Api key for the ewww converter. The option is actually called *api-key*, however, any option can be prefixed with a converter id to only apply to that converter. As this option is only for the ewww converter, it is natural to use the "ewww-" prefix.
|
95 |
+
|
96 |
+
Note: This option can alternatively be set through the *EWWW_API_KEY* environment variable.<br><br>
|
97 |
+
|
98 |
+
### `ewww-check-key-status-before-converting`
|
99 |
+
```
|
100 |
+
Type: boolean
|
101 |
+
Default: true
|
102 |
+
Supported by: ewww
|
103 |
+
```
|
104 |
+
Decides whether or not the ewww service should be invoked in order to check if the api key is valid. Doing this for every conversion is not optimal. However, it would be worse if the service was contacted repeatedly to do conversions with an invalid api key - as conversion requests carries a big upload with them. As this library cannot prevent such repeated failures (it is stateless), it per default does the additional check. However, your application can prevent it from happening by picking up invalid / exceeded api keys discovered during conversion. Such failures are stored in `Ewww::$nonFunctionalApiKeysDiscoveredDuringConversion` (this is also set even though a converter later in the stack succeeds. Do not only read this value off in a catch clauses).
|
105 |
+
|
106 |
+
You should only set this option to *false* if you handle when the converter discovers invalid api keys during conversion.
|
107 |
+
|
108 |
+
### `jpeg`
|
109 |
+
```
|
110 |
+
Type: array
|
111 |
+
Default: []
|
112 |
+
Supported by: all
|
113 |
+
```
|
114 |
+
Override selected options when the source is a jpeg. The options provided here are simply merged into the other options when the source is a jpeg.
|
115 |
+
Read about this option in the [introduction](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md#png-og-jpeg-specific-options).<br><br>
|
116 |
+
|
117 |
+
### `log-call-arguments`
|
118 |
+
```
|
119 |
+
Type: boolean
|
120 |
+
Default: false
|
121 |
+
Supported by: all
|
122 |
+
```
|
123 |
+
Enabling this simply puts some more in the log - namely the arguments that was supplied to the call. Sensitive information is starred out.
|
124 |
+
|
125 |
+
### `low-memory`
|
126 |
+
```
|
127 |
+
Type: boolean
|
128 |
+
Default: false
|
129 |
+
Supported by: cwebp, imagick, imagemagick and graphicsmagick
|
130 |
+
```
|
131 |
+
Reduce memory usage of lossy encoding at the cost of ~30% longer encoding time and marginally larger output size. Read more in [the docs](https://developers.google.com/speed/webp/docs/cwebp).<br><br>
|
132 |
+
|
133 |
+
### `max-quality`
|
134 |
+
```
|
135 |
+
Type: integer (0-100)
|
136 |
+
Default: 85
|
137 |
+
Supported by: all (cwebp, ewww, ffmpeg, gd, gmagick, graphicsmagick, imagick, imagemagick, vips)
|
138 |
+
```
|
139 |
+
Read about this option in the ["auto quality" section in the introduction](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md#auto-quality).<br><br>
|
140 |
+
|
141 |
+
### `metadata`
|
142 |
+
```
|
143 |
+
Type: string ("all" | "none" | "exif" | "icc" | "xmp")
|
144 |
+
Default: 'none'
|
145 |
+
Supported by: 'none' is supported by all. 'all' is supported by all, except *gd* and *ffmpeg*. The rest is only supported by *cwebp*
|
146 |
+
```
|
147 |
+
Only *cwebp* supports all values. *gd* will always remove all metadata. The rest can either strip all or keep all (they will keep all, unless the option is set to *none*).<br><br>
|
148 |
+
|
149 |
+
### `method`
|
150 |
+
```
|
151 |
+
Type: integer (0-6)
|
152 |
+
Default: 6
|
153 |
+
Supported by: cwebp, imagick, gmagick, imagemagick, graphicsmagick and ffmpeg
|
154 |
+
```
|
155 |
+
This parameter controls the trade off between encoding speed and the compressed file size and quality. Possible values range from 0 to 6. 0 is fastest. 6 results in best quality. In ffmpeg, this value is used for the "compression_level" option (same thing)<br><br>
|
156 |
+
|
157 |
+
### `near-lossless`
|
158 |
+
```
|
159 |
+
Type: integer (0-100)
|
160 |
+
Default: 60
|
161 |
+
Supported by: cwebp, vips
|
162 |
+
```
|
163 |
+
Specify the level of near-lossless image preprocessing. This option adjusts pixel values to help compressibility, but has minimal impact on the visual quality. It triggers lossless compression mode automatically. The range is 0 (maximum preprocessing) to 100 (no preprocessing). The typical value is around 60. Read more [here](https://groups.google.com/a/webmproject.org/forum/#!topic/webp-discuss/0GmxDmlexek).<br><br>
|
164 |
+
|
165 |
+
### `png`
|
166 |
+
```
|
167 |
+
Type: array
|
168 |
+
Default: []
|
169 |
+
Supported by: all
|
170 |
+
```
|
171 |
+
Override selected options when the source is a png. The options provided here are simply merged into the other options when the source is a png.
|
172 |
+
Read about this option in the [introduction](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md#png-og-jpeg-specific-options).<br><br>
|
173 |
+
|
174 |
+
### `preset`
|
175 |
+
```
|
176 |
+
Type: string ('none', 'default', 'photo', 'picture', 'drawing', 'icon' or 'text')
|
177 |
+
Default: "none"
|
178 |
+
Supported by: cwebp, vips, ffmpeg
|
179 |
+
```
|
180 |
+
Using a preset will set many of the other options to suit a particular type of source material. It even overrides them. It does however not override the quality option. "none" means that no preset will be set<br><br>
|
181 |
+
|
182 |
+
### `quality`
|
183 |
+
```
|
184 |
+
Type: integer (0-100) | "auto"
|
185 |
+
Default: "auto" for jpegs and 85 for pngs
|
186 |
+
Supported by: all (cwebp, ewww, gd, gmagick, graphicsmagick, imagick, imagemagick, vips, ffmpeg)
|
187 |
+
```
|
188 |
+
Quality for lossy encoding. Read about the "auto" option in the [introduction](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md#auto-quality).<br><br>
|
189 |
+
|
190 |
+
### `size-in-percentage`
|
191 |
+
```
|
192 |
+
Type: integer (0-100) | null
|
193 |
+
Default: null
|
194 |
+
Supported by: cwebp
|
195 |
+
```
|
196 |
+
This option sets the file size, *cwebp* should aim for, in percentage of the original. If you for example set it to *45*, and the source file is 100 kb, *cwebp* will try to create a file with size 45 kb (we use the `-size` option). This is an excellent alternative to the "quality:auto" option. If the quality detection isn't working on your system (and you do not have the rights to install imagick or gmagick), you should consider using this options instead. *Cwebp* is generally able to create webp files with the same quality at about 45% the size. So *45* would be a good choice. The option overrides the quality option. And note that it slows down the conversion - it takes about 2.5 times longer to do a conversion this way, than when quality is specified. Default is *off* (null).<br><br>
|
197 |
+
|
198 |
+
### `skip`
|
199 |
+
```
|
200 |
+
Type: boolean
|
201 |
+
Default: false
|
202 |
+
Supported by: all
|
203 |
+
```
|
204 |
+
Simply skips conversion. For example this can be used to skip png conversion for a specific converter like this:
|
205 |
+
```php
|
206 |
+
$options = [
|
207 |
+
'png' => [
|
208 |
+
'gd-skip' => true,
|
209 |
+
]
|
210 |
+
];
|
211 |
+
```
|
212 |
+
|
213 |
+
Or it can be used to skip unwanted converters from the default stack, like this:
|
214 |
+
```php
|
215 |
+
$options = [
|
216 |
+
'ewww-skip' => true,
|
217 |
+
'wpc-skip' => true,
|
218 |
+
'gd-skip' => true,
|
219 |
+
'imagick-skip' => true,
|
220 |
+
'gmagick-skip' => true,
|
221 |
+
];
|
222 |
+
```
|
223 |
+
<br>
|
224 |
+
|
225 |
+
### `stack-converters`
|
226 |
+
```
|
227 |
+
Type: array
|
228 |
+
Default: ['cwebp', 'vips', 'imagick', 'gmagick', 'imagemagick', 'graphicsmagick', 'wpc', 'ewww', 'gd']
|
229 |
+
Supported by: stack
|
230 |
+
```
|
231 |
+
|
232 |
+
Specify the converters to try and their order.
|
233 |
+
|
234 |
+
Beware that if you use this option, you will miss out when more converters are added in future updates. If the purpose of setting this option is to remove converters that you do not want to use, you can use the *skip* option instead. Ie, to skip ewww, set *ewww-skip* to true. On the other hand, if what you actually want is to change the order, you can use the *stack-preferred-converters* option, ie setting *stack-preferred-converters* to `['vips', 'wpc']` will move vips and wpc in front of the others. Should they start to fail, you will still have the others as backup.
|
235 |
+
|
236 |
+
The array specifies the converters to try and their order. Each item can be:
|
237 |
+
|
238 |
+
- An id (ie "cwebp")
|
239 |
+
- A fully qualified class name (in case you have programmed your own custom converter)
|
240 |
+
- An array with two keys: "converter" and "options".
|
241 |
+
|
242 |
+
`
|
243 |
+
Alternatively, converter options can be set using the *converter-options* option.
|
244 |
+
|
245 |
+
Read more about the stack converter in the [introduction](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md#the-stack-converter).<br><br>
|
246 |
+
|
247 |
+
### `stack-converter-options`
|
248 |
+
```
|
249 |
+
Type: array
|
250 |
+
Default: []
|
251 |
+
Supported by: stack
|
252 |
+
```
|
253 |
+
Extra options for specific converters. Example:
|
254 |
+
|
255 |
+
```php
|
256 |
+
$options = [
|
257 |
+
'converter-options' => [
|
258 |
+
'vips' => [
|
259 |
+
'quality' => 72
|
260 |
+
],
|
261 |
+
]
|
262 |
+
]
|
263 |
+
```
|
264 |
+
<br>
|
265 |
+
|
266 |
+
### `stack-extra-converters`
|
267 |
+
```
|
268 |
+
Type: array
|
269 |
+
Default: []
|
270 |
+
Supported by: stack
|
271 |
+
```
|
272 |
+
Add extra converters to the bottom of the stack. The items are similar to those in the `stack-converters` option.<br><br>
|
273 |
+
|
274 |
+
### `stack-preferred-converters`
|
275 |
+
```
|
276 |
+
Type: array
|
277 |
+
Default: []
|
278 |
+
Supported by: stack
|
279 |
+
```
|
280 |
+
With this option you can move specified converters to the top of the stack. The converters are specified by id. For example, setting this option to ['vips', 'wpc'] ensures that *vips* will be tried first and - in case that fails - *wpc* will be tried. The rest of the converters keeps their relative order.<br><br>
|
281 |
+
|
282 |
+
### `stack-shuffle`
|
283 |
+
```
|
284 |
+
Type: boolean
|
285 |
+
Default: false
|
286 |
+
Supported by: stack
|
287 |
+
```
|
288 |
+
Shuffle the converters in the stack. This can for example be used to balance load between several wpc instances in a substack, as illustrated [here](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/converters/stack.md)<br><br>
|
289 |
+
|
290 |
+
### `use-nice`
|
291 |
+
```
|
292 |
+
Type: boolean
|
293 |
+
Default: false
|
294 |
+
Supported by: cwebp, graphicsmagick, imagemagick, ffmpeg
|
295 |
+
```
|
296 |
+
This option only applies to converters which are using exec() to execute a binary directly on the host. If *use-nice* is set, it will be examined if the [`nice`]( https://en.wikipedia.org/wiki/Nice_(Unix)) command is available on the host. If it is, the binary is executed using *nice*. This assigns low priority to the process and will save system resources - but result in slower conversion.<br><br>
|
297 |
+
|
298 |
+
### `vips-smart-subsample`
|
299 |
+
```
|
300 |
+
Type: boolean
|
301 |
+
Default: false
|
302 |
+
Supported by: vips
|
303 |
+
```
|
304 |
+
This feature seems not to be part of *libwebp* but intrinsic to vips. According to the [vips docs](https://jcupitt.github.io/libvips/API/current/VipsForeignSave.html#vips-webpsave), it enables high quality chroma subsampling.<br><br>
|
305 |
+
|
306 |
+
### `wpc-api-key`
|
307 |
+
```
|
308 |
+
Type: string
|
309 |
+
Default: ''
|
310 |
+
Supported by: wpc
|
311 |
+
```
|
312 |
+
Api key for the wpc converter. The option is actually called *api-key*, however, any option can be prefixed with a converter id to only apply to that converter. As this option is only for the wpc converter, it is natural to use the "wpc-" prefix. Same goes for the other "wpc-" options.
|
313 |
+
|
314 |
+
Note: You can alternatively set the api key through the *WPC_API_KEY* environment variable.<br><br>
|
315 |
+
|
316 |
+
### `wpc-api-url`
|
317 |
+
```
|
318 |
+
Type: string
|
319 |
+
Default: ''
|
320 |
+
Supported by: wpc
|
321 |
+
```
|
322 |
+
Note: You can alternatively set the api url through the *WPC_API_URL* environment variable.<br><br>
|
323 |
+
|
324 |
+
### `wpc-api-version`
|
325 |
+
```
|
326 |
+
Type: integer (0 - 1)
|
327 |
+
Default: 0
|
328 |
+
Supported by: wpc
|
329 |
+
```
|
330 |
+
<br>
|
331 |
+
|
332 |
+
### `wpc-crypt-api-key-in-transfer`
|
333 |
+
```
|
334 |
+
Type: boolean
|
335 |
+
Default: false
|
336 |
+
Supported by: wpc
|
337 |
+
```
|
338 |
+
<br>
|
339 |
+
|
340 |
+
### `wpc-secret`
|
341 |
+
```
|
342 |
+
Type: string
|
343 |
+
Default: ''
|
344 |
+
Supported by: wpc
|
345 |
+
```
|
346 |
+
Note: This option is only relevant for api version 0.
|
vendor/rosell-dk/webp-convert/docs/v2.0/migrating-to-2.0.md
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
convert# Migrating to 2.0
|
2 |
+
|
3 |
+
## Converting
|
4 |
+
|
5 |
+
### Changes in conversion api
|
6 |
+
While the code have been refactored quite extensively, if you have stuck to `WebPConvert::convert()` and/or `WebPConvert::convertAndServe()`, there is only a few things you need to know.
|
7 |
+
|
8 |
+
First and foremost: *`WebPConvert::convert` no longer returns a boolean indicating the result*. So, if conversion fails, an exception is thrown, no matter what the reason is. When migrating, you will probably need to remove some lines of code where you test the result.
|
9 |
+
|
10 |
+
Also, a few options has been renamed and a few option defaults has been changed.
|
11 |
+
|
12 |
+
#### The options that has been renamed are the following:
|
13 |
+
|
14 |
+
- Two converters have changed IDs and class names: The ids that are changed are: *imagickbinary* => *imagemagick* and *gmagickbinary* => *graphicsmagick*
|
15 |
+
- In *ewww*, the `key` option has been renamed to `api-key` (or [`ewww-api-key`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#ewww-api-key))
|
16 |
+
- In *wpc*, the `url` option has been renamed to `api-url` (or [`wpc-api-url`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#wpc-api-url))
|
17 |
+
* In *cwebp*, the [`lossless`] option is now replaced with the new `encoding` option (which is not boolean, but "lossy", "lossless" or ["auto"](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md#auto-selecting-between-losslesslossy-encoding))
|
18 |
+
* In *cwebp*, the [`autofilter`] option has been renamed to "auto-filter"
|
19 |
+
- In *gd*, the `skip-pngs` option has been removed and replaced with the general `skip` option and prefixing. So `gd-skip` amounts to the same thing, but notice that Gd no longer skips per default.
|
20 |
+
|
21 |
+
#### The option defaults that has been changed are the following:
|
22 |
+
- the `converters` default now includes the cloud converters (*ewww* and *wpc*) and also two new converters, *vips* and *graphicsmagick*. So it is not necessary to add *ewww* or *wpc* explicitly. Also, when you set options with `converter-options` and point to a converter that isn't in the stack, in 1.3.9, this resulted in the converter automatically being added. This behavior has been removed.
|
23 |
+
- *gd* no longer skips pngs per default. To make it skip pngs, set `gd-skip` to *true*
|
24 |
+
- Default quality is now 75 for jpegs and 85 for pngs (it was 75 for both)
|
25 |
+
- For *cwebp*, the `lossless` has been removed. Use the new `encoding` option instead.
|
26 |
+
- For *wpc*, default `secret` and `api-key` are now "" (they were "my dog is white")
|
27 |
+
|
28 |
+
### New convert options
|
29 |
+
You might also be interested in the new options available in 2.0:
|
30 |
+
|
31 |
+
- Added a syntax for conveniently targeting specific converters. If you for example prefix the "quality" option with "gd-", it will override the "quality" option, but only for gd.
|
32 |
+
- Certain options can now be set with environment variables too ("EWWW_API_KEY", "WPC_API_KEY" and "WPC_API_URL")
|
33 |
+
- Added new *vips* converter.
|
34 |
+
- Added new *graphicsmagick* converter.
|
35 |
+
- Added new *stack* converter (the stack functionality has been moved into a converter)
|
36 |
+
- Added [`jpeg`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#jpeg) and [`png`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#png) options
|
37 |
+
- Added [`alpha-quality`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#alpha-quality) option for *cwebp*, *vips*, *imagick*, *imagemagick* and *graphicsmagick*.
|
38 |
+
- Added [`auto-filter`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#autofilter) option for *cwebp*, *imagick*, *imagemagick* and the new *vips* converter.
|
39 |
+
- Added [`encoding`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#encoding) option (lossy | lossless | auto). lossless and auto is supported for *cwebp*, *imagick*, *imagemagick*, *graphicsmagick* and the new *vips* converter.
|
40 |
+
- Added [`near-lossless`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#near-lossless) option for *cwebp* and *imagemagick*.
|
41 |
+
- Added [`preset`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#preset) option for *cwebp* and the new *vips* converter.
|
42 |
+
- Added [`skip`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#skip) option (its general and works for all converters)
|
43 |
+
- Besides the ones mentioned above, *imagemagick* now also supports [`low-memory`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#low-memory), [`metadata`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#metadata) ("all" or "none") and [`method`](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/options.md#method). *imagemagick* has become very potent!
|
44 |
+
|
45 |
+
## Serving
|
46 |
+
The classes for serving has also been refactored quite extensively, but again, if you have stuck to `WebPConvert::convertAndServe`, there is only a few things you need to know.
|
47 |
+
|
48 |
+
First and foremost, *`WebPConvert::convertAndServe` has been renamed to `WebPConvert::serveConverted()`*. The reason for this change is that it more accurately describes what is happening: A converted file is served. The old name implied that a conversion was always going on, which is not the case (if the file at destination already exists, which is not bigger or older than the source, that file is served directly).
|
49 |
+
|
50 |
+
Besides this, there is the following changes in options:
|
51 |
+
|
52 |
+
- A new option `convert` has been created for supplying the conversion options. So the conversion options are no longer "mingled" with the serving options, but has its own option.
|
53 |
+
- Options regarding serving the image are now organized into its own `serve-image` setting, which again has been reorganized.
|
54 |
+
- A new option `serve-image > headers > cache-control` controls whether to set cache control header (default: false).
|
55 |
+
- The `fail` option no longer support the "report-as-image" value. It however supports a new value: "throw".
|
56 |
+
- The `fail-when-original-unavailable` option has been renamed to `fail-when-fail-fails`. In 2.0, the original not being available is no longer the only thing that can cause the fail action to fail – the library now checks the mime type of the source file and only serves it if it is either png or jpeg.
|
57 |
+
- The `error-reporting` option has been removed. The reason for it being removed is that it is considered bad practice for a library to mess with error handling. However, *this pushes the responsibility to you*. You should make sure that no warnings ends up in the output, as this will corrupt the image being served. You can for example ensure that by calling `ini_set('display_errors', '0');` or `error_reporting(0);` (or both), or by creating your own error handler.
|
58 |
+
- The `aboutToServeImageCallBack` option has been removed. You can instead extend the `ServeConvertedWebP` class and override `serveOriginal` and `serveDestination`. You can call the serve method of your extended class, but then you will not have the error handling (the `fail` and `fail-if-fail-fails` options). Too add this, you can call `ServeConvertedWebPWithErrorHandling::serve` and make sure to override the default of the last argument.
|
59 |
+
- The `aboutToPerformFailAction` option has been removed. You can instead set `fail` to `throw` and handle the exception in a *catch* clause. Or you can extend the `ServeConvertedWebPWithErrorHandling` class and override the `performFailAction` method.
|
60 |
+
- The `add-x-header-status` and `add-x-header-options` options have been removed.
|
61 |
+
- The `require-for-conversion` option has been removed. You must either use with composer or create a simple autoloader (see next section)
|
62 |
+
|
63 |
+
## WebP On demand
|
64 |
+
If you are using the "non-composer" version of webp demand (the one where you only upload two files - `webp-on-demand-1.inc` and `webp-on-demand-2.inc`), you were probably using the `require-for-conversion` option. This option is no longer supported. But you never really needed it in the first place, because the you create and register an autoloader instead:
|
65 |
+
|
66 |
+
```php
|
67 |
+
function autoloader($class) {
|
68 |
+
if (strpos($class, 'WebPConvert\\') === 0) {
|
69 |
+
require_once __DIR__ . '/webp-on-demand-2.inc';
|
70 |
+
}
|
71 |
+
}
|
72 |
+
spl_autoload_register('autoloader', true, true);
|
73 |
+
```
|
vendor/rosell-dk/webp-convert/docs/v2.0/serving/introduction-for-serving.md
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Introduction to serving converted WebP files with WebPConvert
|
2 |
+
|
3 |
+
**NOTE: This document only applies to the upcoming 2.0 version**
|
4 |
+
|
5 |
+
The classes for serving first and foremost helps you handle the cached files intelligently (not serving them if they are larger or older than the original). It also provides a convenient way to deal with conversion failures and setting headers.
|
6 |
+
|
7 |
+
|
8 |
+
In the following example, all available *serve* options are explicitly set to their default values.
|
9 |
+
|
10 |
+
```php
|
11 |
+
use WebPConvert\WebPConvert;
|
12 |
+
|
13 |
+
WebPConvert::serveConverted($source, $destination, [
|
14 |
+
|
15 |
+
// failure handling
|
16 |
+
'fail' => 'original', // ('original' | 404' | 'throw' | 'report')
|
17 |
+
'fail-when-fail-fails' => 'throw', // ('original' | 404' | 'throw' | 'report')
|
18 |
+
|
19 |
+
// options influencing the decision process of what to be served
|
20 |
+
'reconvert' => false, // if true, existing (cached) image will be discarded
|
21 |
+
'serve-original' => false, // if true, the original image will be served rather than the converted
|
22 |
+
'show-report' => false, // if true, a report will be output rather than the raw image
|
23 |
+
|
24 |
+
// warning handling
|
25 |
+
'suppress-warnings' => true, // if you set to false, make sure that warnings are not echoed out!
|
26 |
+
|
27 |
+
// options when serving an image (be it the webp or the original, if the original is smaller than the webp)
|
28 |
+
'serve-image' => [
|
29 |
+
'headers' => [
|
30 |
+
'cache-control' => true,
|
31 |
+
'content-length' => true,
|
32 |
+
'content-type' => true,
|
33 |
+
'expires' => false,
|
34 |
+
'last-modified' => true,
|
35 |
+
'vary-accept' => false
|
36 |
+
],
|
37 |
+
'cache-control-header' => 'public, max-age=31536000',
|
38 |
+
],
|
39 |
+
|
40 |
+
// redirect tweak
|
41 |
+
'redirect-to-self-instead-of-serving' => false, // if true, a redirect will be issues rather than serving
|
42 |
+
|
43 |
+
'convert' => [
|
44 |
+
// options for converting goes here
|
45 |
+
'quality' => 'auto',
|
46 |
+
]
|
47 |
+
]);
|
48 |
+
```
|
49 |
+
|
50 |
+
## Failure handling
|
51 |
+
The `fail` option gives you an easy way to handle errors. Setting it to 'original' tells it to handle errors by serving the original file instead (*$source*). This could be a good choice on production servers. On development servers, 'throw' might be a good option. It simply rethrows the exception that was thrown by *WebPConvert::convert()*. '404' could also be an option, but it has the weakness that it will probably only be discovered by real persons seeing a missing image.
|
52 |
+
|
53 |
+
The fail action might fail too. For example, if it is set to 'original' and the failure is that the original file doesn't exist. Or, more delicately, it may have a wrong mime type - our serve method will not let itself be tricked into serving *exe* files as the 'original'. Anyway, you can control what to do when fail fails using the *fail-when-fail-fails* option. If that fails too, the original exception is thrown. The fun stops there, there is no "fail-when-fail-when-fail-fails" option to customize this.
|
54 |
+
|
55 |
+
The failure handling is implemented as an extra layer. You can bypass it by calling `WebPConvert\Serve\ServeConvertedWebP::serve()` directly. Doing that will give the same result as if you set `fail` to 'throw'.
|
56 |
+
|
57 |
+
## Options influencing the decision process
|
58 |
+
The default process is like this:
|
59 |
+
|
60 |
+
1. Is there a file at the destination? If not, trigger conversion
|
61 |
+
2. Is the destination older than the source? If yes, delete destination and trigger conversion
|
62 |
+
3. Serve the smallest file (destination or source)
|
63 |
+
|
64 |
+
You can influence the process with the following options:
|
65 |
+
|
66 |
+
*reconvert*
|
67 |
+
If you set *reconvert* to true, the destination and conversion is triggered (between step 1 and 2)
|
68 |
+
|
69 |
+
*serve-original*
|
70 |
+
If you set *serve-original* to true, process will take its cause from (1) to (2) and then end with source being served.
|
71 |
+
|
72 |
+
*show-report*
|
73 |
+
If you set `show-report`, the process is skipped entirely, and instead a report is generated of how a fresh conversion using the supplied options goes.
|
74 |
+
|
75 |
+
## Headers
|
76 |
+
Leaving errors and reports out of account for a moment, the *WebPConvert::serveConverted()* ultimately has two possible outcomes: Either a converted image is served or - if smaller - the source image. If the source is to be served, its mime type will be detected in order to make sure it is an image and to be able to set the content type header. Either way, the actual serving is passed to `Serve\ServeFile::serve`. The main purpose of this class is to add/set headers.
|
77 |
+
|
78 |
+
#### *Cache-Control* and *Expires* headers
|
79 |
+
Default behavior is to neither set the *Cache-Control* nor the *Expires* header. Once you are on production, you will probably want to turn these on. The default is btw one year (31536000 seconds). I recommend the following for production:
|
80 |
+
|
81 |
+
```
|
82 |
+
'serve-image' => [
|
83 |
+
'headers' => [
|
84 |
+
'cache-control' => true,
|
85 |
+
'expires' => false,
|
86 |
+
],
|
87 |
+
'cache-control-header' => 'public, max-age=31536000',
|
88 |
+
],
|
89 |
+
```
|
90 |
+
|
91 |
+
The value for the *Expires* header is calculated from "max-age" found in the *cache-control-header* option and the time of the request. The result is an absolute time, ie "Expires: Thu, 07 May 2020 07:02:37 GMT". As most browsers now supports the *Cache-Control* header, *from a performance perspective*, there is no need to also add the expires header. However, some tools complains if you don't (gtmetrix allegedly), and there is no harm in adding both headers. More on this discussion [[here]](https://github.com/rosell-dk/webp-convert/issues/126).
|
92 |
+
|
93 |
+
#### *Vary: Accept* header
|
94 |
+
This library can be used as part of a solution that serves webp files to browsers that supports it, while serving the original file to browsers that does not *on the same URL*. Such a solution typically inspects the *Accept* request header in order to determine if the client supports webp or not. Thus, the response will *vary* along with the "Accept" header and the world (and proxies) should be informed about this, so they don't end up serving cached webps to browsers that does not support it. To add the "Vary: Accept" header, simply set the *serve-image > headers > vary-accept* option to true.
|
95 |
+
|
96 |
+
#### *Last-Modified* header
|
97 |
+
The Last-Modified header is also used for caching purposes. You should leave that setting on, unless you set it by other means. You control it with the *serve-image > headers > last-modified* option.
|
98 |
+
|
99 |
+
#### *Content-Type* header
|
100 |
+
The *Content-Type* header tells browsers what they are receiving. This is important information and you should leave the *serve-image > headers > content-type* option at its default (true), unless you set it by other means.
|
101 |
+
|
102 |
+
When the outcome is to serve a webp, the header will be set to: "Content-Type: image/webp". When the original is to be served, the library will try to detect the mime type of the file and set the content type accordingly. The [image-mime-type-guesser](https://github.com/rosell-dk/image-mime-type-guesser) library is used for that.
|
103 |
+
|
104 |
+
#### *Content-Length* header
|
105 |
+
The *Content-Length* header tells browsers the length of the content. According to [the specs](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13), it should be set unless it is prohibited by rules in [section 4.4](https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4). In that section we learn that it should not be set when the *Transfer-Encoding* header is set (which it often is, to "chunked"). However, no harm done, because it also says that clients should ignore the header in case *Transfer-Encoding* is set. From this I concluded that it makes sense to default the *serve-image > headers > content-length* to true. I might however change this in case I should learn that the header could be problematic in some way. So if you decided you want it, do not rely on the default, but set it to *true*. See discussion on this subject [here](https://stackoverflow.com/questions/3854842/content-length-header-with-head-requests/3854983#3854983).
|
106 |
+
|
107 |
+
#### *X-WebP-Convert-Log* headers
|
108 |
+
The serve method adds *X-WebP-Convert-Log* headers in order to let you know what went on.
|
109 |
+
For example, if there is no converted image and conversion was successful, the following headers will be sent:
|
110 |
+
|
111 |
+
```
|
112 |
+
X-WebP-Convert-Log: Converting (there were no file at destination)
|
113 |
+
X-WebP-Convert-Log: Serving converted file
|
114 |
+
```
|
115 |
+
|
116 |
+
On the next call (presuming the webp has not been deleted), no conversion is needed and you should simply see:
|
117 |
+
```
|
118 |
+
X-WebP-Convert-Log: Serving converted file
|
119 |
+
```
|
120 |
+
|
121 |
+
But say that the first conversion actually failed. In case you have permission problems, the output could be:
|
122 |
+
```
|
123 |
+
X-WebP-Convert-Log: Converting (there were no file at destination)
|
124 |
+
X-WebP-Convert-Log: Failed creating folder. Check the permissions!
|
125 |
+
X-WebP-Convert-Log: Performing fail action: original
|
126 |
+
```
|
127 |
+
|
128 |
+
In case the problem is that the conversion failed, you could see the following:
|
129 |
+
```
|
130 |
+
X-WebP-Convert-Log: Converting (there were no file at destination)
|
131 |
+
X-WebP-Convert-Log: None of the converters in the stack are operational
|
132 |
+
X-WebP-Convert-Log: Performing fail action: original
|
133 |
+
```
|
134 |
+
|
135 |
+
If you need more info about the conversion process in order to learn why the converters aren't working, enable the *show-report* option.
|
136 |
+
|
137 |
+
As a last example, say you have supplied a non-existing file as source and `fail` is set to "original" (which will also fail). Result:
|
138 |
+
```
|
139 |
+
X-WebP-Convert-Log: Source file was not found
|
140 |
+
X-WebP-Convert-Log: Performing fail action: original
|
141 |
+
X-WebP-Convert-Log: Performing fail action: throw
|
142 |
+
```
|
143 |
+
|
144 |
+
## The redirect tweak (will be available in 2.3.0)
|
145 |
+
There are cases where serving the image directly with PHP isn't optimal.
|
146 |
+
|
147 |
+
One case is WP Engine. Even though webp-convert adds a Vary:Accept header, the header is not present in the response on WP Engine. It is somehow overwritten by the caching machinery and set to Vary:Accept-Encoding, Cookie.
|
148 |
+
|
149 |
+
If however rules have been set up to redirect images directly to existing webps, one can overcome the problem by redirecting the image request back to itself rather than serving the webp directly.
|
150 |
+
|
151 |
+
You can achieve this by setting the *redirect-to-self-instead-of-serving* option to true.
|
152 |
+
|
153 |
+
Beware of risk of an endless redirect loop. Such loop will happen if the redirection to existing webp rules aren't set up correctly. To prevent this, it is recommended that you only set the option to true after checking that the destination file does not exist. But note that this check does not completely prevent such loops occurring when redirection to existing rules are missing - as the 302 redirect could get cached (it does that on WP Engine). So bottom line: Only use this feature when you have server rules set up for redirecting images to their corresponding webp images (for client that supports webp) - *and you are certain that these rules works*.
|
154 |
+
|
155 |
+
## More info
|
156 |
+
|
157 |
+
- The complete api is available [here](https://www.bitwise-it.dk/webp-convert/api/2.0/html/index.xhtml)
|
vendor/rosell-dk/webp-convert/docs/v2.0/serving/laravel-nginx-serving.md
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Serving WebP from a Laravel Nginx site
|
2 |
+
|
3 |
+
**NOTE: This document only applies to the upcoming 2.0 version**
|
4 |
+
|
5 |
+
This should work with most php sites although I'm basing the Nginx configuration around what's commonly seen with Laravel installations.
|
6 |
+
|
7 |
+
Create webp converter script in ```project_root/public/webp-on-demand.php```
|
8 |
+
|
9 |
+
```
|
10 |
+
<?php
|
11 |
+
|
12 |
+
require '../vendor/autoload.php';
|
13 |
+
|
14 |
+
use WebPConvert\WebPConvert;
|
15 |
+
|
16 |
+
$source = __DIR__ . $_GET['source'];
|
17 |
+
$destination = $source . '.webp';
|
18 |
+
|
19 |
+
WebPConvert::serveConverted($source, $destination, [
|
20 |
+
'fail' => 'original', // If failure, serve the original image (source). Other options include 'throw', '404' and 'report'
|
21 |
+
// 'show-report' => true, // Generates a report instead of serving an image
|
22 |
+
|
23 |
+
'serve-image' => [
|
24 |
+
'headers' => [
|
25 |
+
'cache-control' => true,
|
26 |
+
'vary-accept' => true,
|
27 |
+
// other headers can be toggled...
|
28 |
+
],
|
29 |
+
'cache-control-header' => 'max-age=2',
|
30 |
+
],
|
31 |
+
|
32 |
+
'convert' => [
|
33 |
+
// all convert option can be entered here (ie "quality")
|
34 |
+
],
|
35 |
+
]);
|
36 |
+
|
37 |
+
```
|
38 |
+
|
39 |
+
|
40 |
+
### Configure Nginx
|
41 |
+
|
42 |
+
We just need to add the following block to our site in ```/etc/sites-enabled/```
|
43 |
+
|
44 |
+
```
|
45 |
+
location ~* ^/.*\.(png|jpe?g)$ {
|
46 |
+
add_header Vary Accept;
|
47 |
+
expires 365d;
|
48 |
+
if ($http_accept !~* "webp"){
|
49 |
+
break;
|
50 |
+
}
|
51 |
+
try_files
|
52 |
+
$uri.webp
|
53 |
+
/webp-on-demand.php?source=$uri
|
54 |
+
;
|
55 |
+
}
|
56 |
+
```
|
57 |
+
|
58 |
+
Then reload Nginx ```sudo systemctl restart nginx```
|
59 |
+
|
60 |
+
The full Nginx block should look like
|
61 |
+
|
62 |
+
```
|
63 |
+
server {
|
64 |
+
server_name webp-testing.com;
|
65 |
+
root /home/forge/webp-testing.com/public;
|
66 |
+
|
67 |
+
index index.html index.htm index.php;
|
68 |
+
|
69 |
+
charset utf-8;
|
70 |
+
|
71 |
+
location / {
|
72 |
+
try_files $uri $uri/ /index.php?$query_string;
|
73 |
+
}
|
74 |
+
|
75 |
+
location ~* ^/.*\.(png|jpe?g)$ {
|
76 |
+
add_header Vary Accept;
|
77 |
+
expires 365d;
|
78 |
+
if ($http_accept !~* "webp"){
|
79 |
+
break;
|
80 |
+
}
|
81 |
+
try_files
|
82 |
+
$uri.webp
|
83 |
+
/webp-on-demand.php?source=$uri
|
84 |
+
;
|
85 |
+
}
|
86 |
+
|
87 |
+
location = /favicon.ico { access_log off; log_not_found off; }
|
88 |
+
location = /robots.txt { access_log off; log_not_found off; }
|
89 |
+
|
90 |
+
access_log off;
|
91 |
+
error_log /var/log/nginx/webp-testing.com-error.log error;
|
92 |
+
|
93 |
+
error_page 404 /index.php;
|
94 |
+
|
95 |
+
location ~ \.php$ {
|
96 |
+
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
97 |
+
fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
|
98 |
+
fastcgi_index index.php;
|
99 |
+
include fastcgi_params;
|
100 |
+
}
|
101 |
+
|
102 |
+
location ~ /\.(?!well-known).* {
|
103 |
+
deny all;
|
104 |
+
}
|
105 |
+
|
106 |
+
# cache static assets
|
107 |
+
location ~* \.(gif|ico|css|pdf|svg)$ {
|
108 |
+
expires 365d;
|
109 |
+
}
|
110 |
+
|
111 |
+
location ~* \.(js)$ {
|
112 |
+
add_header Cache-Control no-cache;
|
113 |
+
}
|
114 |
+
|
115 |
+
}
|
116 |
+
```
|
vendor/rosell-dk/webp-convert/docs/v2.0/webp-on-demand/tweaks.md
ADDED
@@ -0,0 +1,181 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Tweaks
|
2 |
+
|
3 |
+
## Store converted images in separate folder
|
4 |
+
|
5 |
+
In most cases, you probably want the cache of converted images to be stored in their own folder rather than have them mingled with the source files.
|
6 |
+
|
7 |
+
To have have the cache folder contain a file structure mirroring the structure of the original files, you can do this:
|
8 |
+
|
9 |
+
```php
|
10 |
+
$applicationRoot = $_SERVER["DOCUMENT_ROOT"]; // If your application is not in document root, you can change accordingly.
|
11 |
+
$imageRoot = $applicationRoot . '/webp-images'; // Change to where you want the webp images to be saved
|
12 |
+
$sourceRel = substr($source, strlen($applicationRoot));
|
13 |
+
$destination = $imageRoot . $sourceRel . '.webp';
|
14 |
+
```
|
15 |
+
|
16 |
+
If your images are stored outside document root (a rare case), you can simply use the complete absolute path:
|
17 |
+
```php
|
18 |
+
$destination = $imageRoot . $source . '.webp'; // pst: $source is an absolute path, and starts with '/'
|
19 |
+
```
|
20 |
+
This will ie store a converted image in */var/www/example.com/public_html/app/webp-images/var/www/example.com/images/logo.jpg.webp*
|
21 |
+
|
22 |
+
If your application can be configured to store outside document root, but rarely is, you can go for this structure:
|
23 |
+
|
24 |
+
```php
|
25 |
+
$docRoot = $_SERVER["DOCUMENT_ROOT"];
|
26 |
+
$imageRoot = $contentDirAbs . '/webp-images';
|
27 |
+
|
28 |
+
if (substr($source, 0, strlen($docRoot)) === $docRoot) {
|
29 |
+
// Source file is residing inside document root.
|
30 |
+
// We can store relative to that.
|
31 |
+
$sourceRel = substr($source, strlen($docRoot));
|
32 |
+
$destination = $imageRoot . '/doc-root' . $sourceRel . '.webp';
|
33 |
+
} else {
|
34 |
+
// Source file is residing outside document root.
|
35 |
+
// we must add complete path to structure
|
36 |
+
$destination = $imageRoot . '/abs' . $source . '.webp';
|
37 |
+
}
|
38 |
+
```
|
39 |
+
|
40 |
+
If you do not know the application root beforehand, and thus do not know the appropriate root for the converted images, see next tweak.
|
41 |
+
|
42 |
+
|
43 |
+
## Get the application root automatically
|
44 |
+
When you want destination files to be put in their own folder, you need to know the root of the application (the folder in which the .htaccess rules resides). In most applications, you know the root. In many cases, it is simply the document root. However, if you are writing an extension, plugin or module to a framework that can be installed in a subfolder, you may have trouble finding it. Many applications have a *index.php* in the root, which can get it with `__DIR__`. However, you do not want to run an entire bootstrap each time you serve an image. Obviously, to get around this, you can place *webp-on-demand.php* in the webroot. However, some frameworks, such as Wordpress, will not allow a plugin to put a file in the root. Now, how could we determine the application root from a file inside some subdir? Here are three suggestions:
|
45 |
+
|
46 |
+
1. You could traverse parent folders until you find a file you expect to be in application root (ie a .htaccess containing the string "webp-on-demand.php"). This should work.
|
47 |
+
2. If the rules in the *.htaccess* file are generated by your application, you probably have access to the path at generation time. You can then simply put the path in the *.htaccess*, as an extra parameter to the script (or better: the relative path from document root to the application).
|
48 |
+
3. You can use the following hack:
|
49 |
+
|
50 |
+
### The hack
|
51 |
+
The idea is to grab the URL path of the image in the *.htaccess* and pass it to the script. Assuming that the URL paths always matches the file paths, we can get the application root by subtracting that relative path to source from the absolute path to source.
|
52 |
+
|
53 |
+
In *.htaccess*, we grab the url-path by appending "&url-path=$1.$2" to the rewrite rule:
|
54 |
+
```
|
55 |
+
RewriteRule ^(.*)\.(jpe?g|png)$ webp-on-demand.php?source=%{SCRIPT_FILENAME}&url-path=$1.$2 [NC,L]
|
56 |
+
```
|
57 |
+
|
58 |
+
In the script, we can then calculate the application root like this:
|
59 |
+
|
60 |
+
```php
|
61 |
+
$applicationRoot = substr($_GET['source'], 0, -strlen($_GET['url-path']));
|
62 |
+
```
|
63 |
+
|
64 |
+
## CDN
|
65 |
+
To work properly with a CDN, a "Vary Accept" header should be added when serving images. This is a declaration that the response varies with the *Accept* header (recall that we inspect *Accept* header in the .htaccess to determine if the browsers supports webp images). If this header is missing, the CDN will see no reason to cache separate images depending on the Accept header.
|
66 |
+
|
67 |
+
Add this snippet to the *.htaccess* to make webp-on-demand work with CDN's:
|
68 |
+
|
69 |
+
```
|
70 |
+
<IfModule mod_headers.c>
|
71 |
+
SetEnvIf Request_URI "\.(jpe?g|png)" ADDVARY
|
72 |
+
|
73 |
+
# Declare that the response varies depending on the accept header.
|
74 |
+
# The purpose is to make CDN cache both original images and converted images.
|
75 |
+
Header append "Vary" "Accept" env=ADDVARY
|
76 |
+
</IfModule>
|
77 |
+
```
|
78 |
+
|
79 |
+
***Note:*** When configuring the CDN, you must make sure to set it up to forward the the "Accept" header to your origin server.
|
80 |
+
|
81 |
+
|
82 |
+
|
83 |
+
## Make .htaccess route directly to existing images
|
84 |
+
|
85 |
+
There may be a performance benefit of using the *.htaccess* file to route to already converted images, instead of letting the PHP script serve it. Note however:
|
86 |
+
- If you do the routing in .htaccess, the solution will not be able to discard converted images when original images are updated.
|
87 |
+
- Performance benefit may be insignificant (*WebPConvertAndServe* class is not autoloaded when serving existing images)
|
88 |
+
|
89 |
+
Add the following to the *.htaccess* to make it route to existing converted images. Place it above the # Redirect images to webp-on-demand.php" comment. Take care of replacing [[your-base-path]] with the directory your *.htaccess* lives in (relative to document root, and [[your-destination-root]] with the directory the converted images resides.
|
90 |
+
```
|
91 |
+
# Redirect to existing converted image (under appropriate circumstances)
|
92 |
+
RewriteCond %{HTTP_ACCEPT} image/webp
|
93 |
+
RewriteCond %{DOCUMENT_ROOT}/[[your-base-path]]/[[your-destination-root]]/$1.$2.webp -f
|
94 |
+
RewriteRule ^\/?(.*)\.(jpe?g|png)$ /[[your-base-path]]/[[your-destination-root]]/$1.$2.webp [NC,T=image/webp,L]
|
95 |
+
```
|
96 |
+
*edit:* Removed the QSD flag from the RewriteRule because it is not supported in Apache < 2.4 (and it [triggers error](https://github.com/rosell-dk/webp-express/issues/155))
|
97 |
+
|
98 |
+
Note however that DOCUMENT_ROOT can be unreliable.
|
99 |
+
|
100 |
+
If you store the webp images in the same folder as the originals and append ".webp" (rather than replace the file extension), you can do this instead:
|
101 |
+
|
102 |
+
```
|
103 |
+
# Redirect to existing converted image (under appropriate circumstances)
|
104 |
+
RewriteCond %{HTTP_ACCEPT} image/webp
|
105 |
+
RewriteCond %{REQUEST_FILENAME}.webp -f
|
106 |
+
RewriteRule ^/?(.+)\.(jpe?g|png)$ $1.$2.webp [T=image/webp,L]
|
107 |
+
```
|
108 |
+
|
109 |
+
|
110 |
+
RewriteCond %{REQUEST_FILENAME}.webp -f
|
111 |
+
|
112 |
+
### Redirect with CDN support
|
113 |
+
If you are using a CDN, and want to redirect to existing images with the .htaccess, it is a good idea to add a "Vary Accept" header. This instructs the CDN that the response varies with the *Accept* header (we do not need to do that when routing to webp-on-demand.php, because the script takes care of adding this header, when appropriate.)
|
114 |
+
|
115 |
+
You can achieve redirect with CDN support with the following rules:
|
116 |
+
```
|
117 |
+
<IfModule mod_rewrite.c>
|
118 |
+
|
119 |
+
RewriteEngine On
|
120 |
+
|
121 |
+
# Redirect to existing converted image (under appropriate circumstances)
|
122 |
+
RewriteCond %{HTTP_ACCEPT} image/webp
|
123 |
+
RewriteCond %{DOCUMENT_ROOT}/[[your-base-path]]/[[your-destination-root]]/$1.$2.webp -f
|
124 |
+
RewriteRule ^\/?(.*)\.(jpe?g|png)$ /[[your-base-path]]/[[your-destination-root]]/$1.$2.webp [NC,T=image/webp,QSD,E=WEBPACCEPT:1,L]
|
125 |
+
|
126 |
+
# Redirect images to webp-on-demand.php (if browser supports webp)
|
127 |
+
RewriteCond %{HTTP_ACCEPT} image/webp
|
128 |
+
RewriteRule ^(.*)\.(jpe?g|png)$ webp-on-demand.php?source=%{SCRIPT_FILENAME}&url-path=$1.$2 [NC,L]
|
129 |
+
|
130 |
+
</IfModule>
|
131 |
+
|
132 |
+
<IfModule mod_headers.c>
|
133 |
+
# Apache appends "REDIRECT_" in front of the environment variables, but LiteSpeed does not.
|
134 |
+
# These next line is for Apache, in order to set environment variables without "REDIRECT_"
|
135 |
+
SetEnvIf REDIRECT_WEBPACCEPT 1 WEBPACCEPT=1
|
136 |
+
|
137 |
+
# Make CDN caching possible.
|
138 |
+
# The effect is that the CDN will cache both the webp image and the jpeg/png image and return the proper
|
139 |
+
# image to the proper clients (for this to work, make sure to set up CDN to forward the "Accept" header)
|
140 |
+
Header append Vary Accept env=WEBPACCEPT
|
141 |
+
</IfModule>
|
142 |
+
|
143 |
+
AddType image/webp .webp
|
144 |
+
```
|
145 |
+
|
146 |
+
## Forward the querystring
|
147 |
+
By forwarding the query string, you can allow control directly from the URL. You could for example make it possible to add "?debug" to an image URL, and thereby getting a conversion report. Or make "?reconvert" force reconversion.
|
148 |
+
|
149 |
+
In order to forward the query string, you need to add this condition before the RewriteRule that redirects to *webp-on-demand.php*:
|
150 |
+
```
|
151 |
+
RewriteCond %{QUERY_STRING} (.*)
|
152 |
+
```
|
153 |
+
That condition will always be met. The side effect is that it stores the match (the complete querystring). That match will be available as %1 in the RewriteRule. So, in the RewriteRule, we will have to add "&%1" after the last argument. Here is a complete solution:
|
154 |
+
```
|
155 |
+
<IfModule mod_rewrite.c>
|
156 |
+
RewriteEngine On
|
157 |
+
|
158 |
+
# Redirect images to webp-on-demand.php (if browser supports webp)
|
159 |
+
RewriteCond %{HTTP_ACCEPT} image/webp
|
160 |
+
RewriteCond %{QUERY_STRING} (.*)
|
161 |
+
RewriteRule ^(.*)\.(jpe?g|png)$ webp-on-demand.php?source=%{SCRIPT_FILENAME}&%1 [NC,L]
|
162 |
+
</IfModule>
|
163 |
+
|
164 |
+
AddType image/webp .webp
|
165 |
+
```
|
166 |
+
|
167 |
+
Of course, in order to *do* something with that querystring, you must use them in your *webp-on-demand.php* script. You could for example use them directly in the options array sent to the *convertAndServe()* method. To achieve the mentioned "debug" and "reconvert" features, do this:
|
168 |
+
```php
|
169 |
+
$options = [
|
170 |
+
'show-report' => isset($_GET['debug']),
|
171 |
+
'reconvert' => isset($_GET['reconvert']),
|
172 |
+
'serve-original' => isset($_GET['original']),
|
173 |
+
];
|
174 |
+
```
|
175 |
+
|
176 |
+
*EDIT:*
|
177 |
+
I have just discovered a simpler way to achieve the querystring forward: The [QSA flag](https://httpd.apache.org/docs/trunk/rewrite/flags.html).
|
178 |
+
So, simply set the QSA flag in the RewriteRule, and nothing more:
|
179 |
+
```
|
180 |
+
RewriteRule ^(.*)\.(jpe?g|png)$ webp-on-demand.php?source=%{SCRIPT_FILENAME} [NC,QSA,L]
|
181 |
+
```
|
vendor/rosell-dk/webp-convert/docs/v2.0/webp-on-demand/webp-on-demand.md
ADDED
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# WebP on demand
|
2 |
+
|
3 |
+
This is a solution for automatically serving WebP images instead of jpeg/pngs [for browsers that supports WebP](https://caniuse.com/#feat=webp) (At the time of writing, 78% of all mobile users and 72% of all desktop users uses browsers supporting webp)
|
4 |
+
|
5 |
+
Once set up, it will automatically convert images, no matter how they are referenced. It for example also works on images referenced in CSS. As the solution does not require any change in the HTML, it can easily be integrated into any website / framework
|
6 |
+
|
7 |
+
## Overview
|
8 |
+
|
9 |
+
A setup consists of a PHP script that serves converted images and some *redirect rules* that redirects JPG/PNG images to the script.
|
10 |
+
|
11 |
+
|
12 |
+
## Requirements
|
13 |
+
|
14 |
+
* *Apache* or *LiteSpeed* web server. Can be made to work with *NGINX* as well. Documentation is on the roadmap.
|
15 |
+
* *mod_rewrite* module for Apache
|
16 |
+
* PHP >= 5.6 (we are only testing down to 5.6. It should however work in 5.5 as well)
|
17 |
+
* That one of the *webp-convert* converters are working (these have different requirements)
|
18 |
+
|
19 |
+
## Installation
|
20 |
+
|
21 |
+
Here we assume you are using Composer. [Not using composer? - Follow me!](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/webp-on-demand/without-composer.md)
|
22 |
+
|
23 |
+
### 1. Require the webp-convert library with composer
|
24 |
+
```
|
25 |
+
composer require rosell-dk/webp-convert
|
26 |
+
```
|
27 |
+
|
28 |
+
### 2. Create the script
|
29 |
+
|
30 |
+
Create a file *webp-on-demand.php*, and place it in webroot, or where-ever you like in you web-application.
|
31 |
+
|
32 |
+
Here is a minimal example to get started with:
|
33 |
+
|
34 |
+
```php
|
35 |
+
<?php
|
36 |
+
// To start with, lets display any errors.
|
37 |
+
// - this will reveal if you entered wrong paths
|
38 |
+
error_reporting(E_ALL);
|
39 |
+
ini_set("display_errors", 1);
|
40 |
+
|
41 |
+
// Once you got it working, make sure that PHP warnings are not send to the output
|
42 |
+
// - this will corrupt the image
|
43 |
+
// For example, you can do it by commenting out the lines below:
|
44 |
+
// error_reporting(0);
|
45 |
+
// ini_set("display_errors", 0);
|
46 |
+
|
47 |
+
require 'vendor/autoload.php'; // Make sure to point this correctly
|
48 |
+
|
49 |
+
use WebPConvert\WebPConvert;
|
50 |
+
|
51 |
+
$source = $_GET['source']; // Absolute file path to source file. Comes from the .htaccess
|
52 |
+
$destination = $source . '.webp'; // Store the converted images besides the original images (other options are available!)
|
53 |
+
|
54 |
+
$options = [
|
55 |
+
|
56 |
+
// UNCOMMENT NEXT LINE, WHEN YOU ARE UP AND RUNNING!
|
57 |
+
'show-report' => true // Show a conversion report instead of serving the converted image.
|
58 |
+
|
59 |
+
// More options available!
|
60 |
+
// https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md
|
61 |
+
// https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/serving/introduction-for-serving.md
|
62 |
+
];
|
63 |
+
WebPConvert::serveConverted($source, $destination, $options);
|
64 |
+
```
|
65 |
+
|
66 |
+
### 3. Add redirect rules
|
67 |
+
Place the following rewrite rules in a *.htaccess* file in the directory where you want the solution to take effect:
|
68 |
+
|
69 |
+
```
|
70 |
+
<IfModule mod_rewrite.c>
|
71 |
+
RewriteEngine On
|
72 |
+
|
73 |
+
# Redirect images to webp-on-demand.php (if browser supports webp)
|
74 |
+
RewriteCond %{HTTP_ACCEPT} image/webp
|
75 |
+
RewriteCond %{REQUEST_FILENAME} -f
|
76 |
+
RewriteRule ^(.*)\.(jpe?g|png)$ webp-on-demand.php?source=%{SCRIPT_FILENAME} [NC,L]
|
77 |
+
</IfModule>
|
78 |
+
|
79 |
+
AddType image/webp .webp
|
80 |
+
```
|
81 |
+
If you have placed *webp-on-demand.php* in a subfolder, you will need to change the rewrite rule accordingly.
|
82 |
+
|
83 |
+
The `RewriteCond %{REQUEST_FILENAME} -f` is not strictly necessary, but there to be sure that we got an existing file, and it could perhaps also prevent some undiscovered way of misuse.
|
84 |
+
|
85 |
+
### 4. Validate that it works
|
86 |
+
|
87 |
+
Browse to a JPEG image. Instead of an image, you should see a conversion report. Hopefully, you get a success. Otherwise, you need to hook up to a cloud converter or try to meet the requirements for cwebp, gd or imagick.
|
88 |
+
|
89 |
+
Once you get a successful conversion, you can uncomment the "show-report" option in the script.
|
90 |
+
|
91 |
+
It should work now, but to be absolute sure:
|
92 |
+
|
93 |
+
- Visit a page on your site with an image on it, using *Google Chrome*.
|
94 |
+
- Right-click the page and choose "Inspect"
|
95 |
+
- Click the "Network" tab
|
96 |
+
- Reload the page
|
97 |
+
- Find a jpeg or png image in the list. In the "type" column, it should say "webp". There should also be a *X-WebP-Convert-Status* header on the image that provides some insights on how things went.
|
98 |
+
|
99 |
+
|
100 |
+
### 5. Try this improvement and see if it works
|
101 |
+
|
102 |
+
It seems that it is not necessary to pass the filename in the query string.
|
103 |
+
|
104 |
+
Try replacing `$source = $_GET['source'];` in the script with the following:
|
105 |
+
|
106 |
+
```php
|
107 |
+
$docRoot = rtrim($_SERVER["DOCUMENT_ROOT"], '/');
|
108 |
+
$requestUriNoQS = explode('?', $_SERVER['REQUEST_URI'])[0];
|
109 |
+
$source = $docRoot . urldecode($requestUriNoQS);
|
110 |
+
```
|
111 |
+
|
112 |
+
And you can then remove `?source=%{SCRIPT_FILENAME}` from the `.htaccess` file.
|
113 |
+
|
114 |
+
There are some benefits of not passing in query string:
|
115 |
+
1. Passing a path in the query string may be blocked by a firewall, as it looks suspicious.
|
116 |
+
2. The script called to convert arbitrary files
|
117 |
+
3. One person experienced problems with spaces in filenames passed in the query string. See [this issue](https://github.com/rosell-dk/webp-convert/issues/95)
|
118 |
+
|
119 |
+
|
120 |
+
### 6. Customizing and tweaking
|
121 |
+
|
122 |
+
Basic customizing is done by setting options in the `$options` array. Check out the [docs on convert()](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/convert.md) and the [docs on convertAndServe()](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/serving/convert-and-serve.md)
|
123 |
+
|
124 |
+
Other tweaking is described in *docs/webp-on-demand/tweaks.md*:
|
125 |
+
- [Store converted images in separate folder](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/webp-on-demand/tweaks.md#store-converted-images-in-separate-folder)
|
126 |
+
- [CDN](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/webp-on-demand/tweaks.md#cdn)
|
127 |
+
- [Make .htaccess route directly to existing images](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/webp-on-demand/tweaks.md#make-htaccess-route-directly-to-existing-images)
|
128 |
+
- [Forward the query string](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/webp-on-demand/tweaks.md#forward-the-querystring)
|
129 |
+
|
130 |
+
|
131 |
+
## Troubleshooting
|
132 |
+
|
133 |
+
### The redirect rule doesn't seem to be working
|
134 |
+
If images are neither routed to the converter or a 404, it means that the redirect rule isn't taking effect. Common reasons for this includes:
|
135 |
+
|
136 |
+
- Perhaps there are other rules in your *.htaccess* that interfere with the rules?
|
137 |
+
- Perhaps your site is on *Apache*, but it has been configured to use *Nginx* to serve image files. To find out which server that is handling the images, browse to an image and eximine the "Server" response header. In case *NGINX* are serving images, see if you can reconfigure your server setup. Alternatively, you can create *NGINX* rewrite rules. There are some [here](https://github.com/S1SYPHOS/kirby-webp#nginx) and [there](https://github.com/uhop/grunt-tight-sprite/wiki/Recipe:-serve-WebP-with-nginx-conditionally).
|
138 |
+
- Perhaps the server isn't configured to allow *.htaccess* files? Try inserting rubbish in the top of the *.htaccess* file and refresh. You should now see an *Internal Server Error* error page. If you don't, your *.htaccess* file is ignored. Probably you will need to set *AllowOverride All* in your Virtual Host. [Look here for more help](
|
139 |
+
https://docs.bolt.cm/3.4/howto/making-sure-htaccess-works#test-if-htaccess-is-working)
|
140 |
+
- Perhaps the Apache *mod_rewrite* extension isn't enabled? Try removing both `<IfModule mod_rewrite.c>` and `</IfModule>` lines: if you get an *Internal Server Error* error page after this change, it's probably that it's indeed not enabled.
|
141 |
+
|
142 |
+
|
143 |
+
## Related
|
144 |
+
* https://www.maxcdn.com/blog/how-to-reduce-image-size-with-webp-automagically/
|
145 |
+
* https://www.digitalocean.com/community/tutorials/how-to-create-and-serve-webp-images-to-speed-up-your-website
|
vendor/rosell-dk/webp-convert/docs/v2.0/webp-on-demand/without-composer.md
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# WebP On Demand without composer
|
2 |
+
|
3 |
+
For your convenience, the library has been cooked down to two files: *webp-on-demand-1.inc* and *webp-on-demand-2.inc*. The second one is loaded when the first one decides it needs to do a conversion (and not simply serve existing image).
|
4 |
+
|
5 |
+
## Installing
|
6 |
+
|
7 |
+
### 1. Copy the latest build files into your website
|
8 |
+
The build files are distributed [here](https://github.com/rosell-dk/webp-convert-concat/tree/master/build). Open the "latest" folder and copy *webp-on-demand-1.inc* and *webp-on-demand-2.inc* into your website. They can be located wherever you like.
|
9 |
+
|
10 |
+
### 2. Create a *webp-on-demand.php*
|
11 |
+
|
12 |
+
Create a file *webp-on-demand.php*, and place it in webroot, or where-ever you like in you web-application.
|
13 |
+
|
14 |
+
Here is a minimal example to get started with:
|
15 |
+
|
16 |
+
```php
|
17 |
+
<?php
|
18 |
+
// To start with, lets display any errors.
|
19 |
+
// - this will reveal if you entered wrong paths
|
20 |
+
error_reporting(E_ALL);
|
21 |
+
ini_set("display_errors", 1);
|
22 |
+
|
23 |
+
// Once you got it working, make sure that PHP warnings are not send to the output
|
24 |
+
// - this will corrupt the image
|
25 |
+
// For example, you can do it by commenting out the lines below:
|
26 |
+
// error_reporting(0);
|
27 |
+
// ini_set("display_errors", 0);
|
28 |
+
|
29 |
+
use WebPConvert\WebPConvert;
|
30 |
+
|
31 |
+
require 'webp-on-demand-1.inc';
|
32 |
+
|
33 |
+
function webpconvert_autoloader($class) {
|
34 |
+
if (strpos($class, 'WebPConvert\\') === 0) {
|
35 |
+
require_once __DIR__ . '/webp-on-demand-2.inc';
|
36 |
+
}
|
37 |
+
}
|
38 |
+
spl_autoload_register('webpconvert_autoloader', true, true);
|
39 |
+
|
40 |
+
$source = $_GET['source']; // Absolute file path to source file. Comes from the .htaccess
|
41 |
+
$destination = $source . '.webp'; // Store the converted images besides the original images (other options are available!)
|
42 |
+
|
43 |
+
$options = [
|
44 |
+
|
45 |
+
// UNCOMMENT NEXT LINE, WHEN YOU ARE UP AND RUNNING!
|
46 |
+
'show-report' => true // Show a conversion report instead of serving the converted image.
|
47 |
+
|
48 |
+
// More options available!
|
49 |
+
// https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md
|
50 |
+
// https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/serving/introduction-for-serving.md
|
51 |
+
];
|
52 |
+
WebPConvert::serveConverted($source, $destination, $options);
|
53 |
+
```
|
54 |
+
|
55 |
+
Note that the procedure has changed in 2.0. In 1.x, the library supported a `require-for-conversion` option, but this option has been removed in 2.0. It was not really needed, as the example above illustrates.
|
56 |
+
|
57 |
+
### 3. Continue the regular install instructions from step 3
|
58 |
+
[Click here to continue...](https://github.com/rosell-dk/webp-on-demand#3-add-redirect-rules)
|
vendor/rosell-dk/webp-convert/src/Convert/ConverterFactory.php
CHANGED
@@ -25,6 +25,9 @@ class ConverterFactory
|
|
25 |
public static function converterIdToClassname($converterId)
|
26 |
{
|
27 |
switch ($converterId) {
|
|
|
|
|
|
|
28 |
case 'imagickbinary':
|
29 |
$classNameShort = 'ImagickBinary';
|
30 |
break;
|
25 |
public static function converterIdToClassname($converterId)
|
26 |
{
|
27 |
switch ($converterId) {
|
28 |
+
case 'ffmpeg':
|
29 |
+
$classNameShort = 'FFMpeg';
|
30 |
+
break;
|
31 |
case 'imagickbinary':
|
32 |
$classNameShort = 'ImagickBinary';
|
33 |
break;
|
vendor/rosell-dk/webp-convert/src/Convert/Converters/Binaries/cwebp-103-linux-x86-64
DELETED
Binary file
|
vendor/rosell-dk/webp-convert/src/Convert/Converters/Binaries/cwebp-103-mac-10_14
DELETED
Binary file
|
vendor/rosell-dk/webp-convert/src/Convert/Converters/Binaries/cwebp-110-linux-x86-64
ADDED
Binary file
|
vendor/rosell-dk/webp-convert/src/Convert/Converters/Binaries/cwebp-110-mac-10_15
ADDED
Binary file
|
vendor/rosell-dk/webp-convert/src/Convert/Converters/Binaries/{cwebp-103-windows-x64.exe → cwebp-110-windows-x64.exe}
RENAMED
Binary file
|
vendor/rosell-dk/webp-convert/src/Convert/Converters/Cwebp.php
CHANGED
@@ -55,10 +55,10 @@ class Cwebp extends AbstractConverter
|
|
55 |
// 2: Set permission to 775. 755 causes unzipping to fail on some hosts
|
56 |
private static $suppliedBinariesInfo = [
|
57 |
'WINNT' => [
|
58 |
-
['cwebp-
|
59 |
],
|
60 |
'Darwin' => [
|
61 |
-
['cwebp-
|
62 |
],
|
63 |
'SunOS' => [
|
64 |
// Got this from ewww Wordpress plugin, which unfortunately still uses the old 0.6.0 versions
|
@@ -73,7 +73,7 @@ class Cwebp extends AbstractConverter
|
|
73 |
'Linux' => [
|
74 |
// Dynamically linked executable.
|
75 |
// It seems it is slightly faster than the statically linked
|
76 |
-
['cwebp-
|
77 |
|
78 |
// Statically linked executable
|
79 |
// It may be that it on some systems works, where the dynamically linked does not (see #196)
|
@@ -89,12 +89,18 @@ class Cwebp extends AbstractConverter
|
|
89 |
*
|
90 |
* This isn't used when converting, but can be used as a startup check.
|
91 |
*/
|
92 |
-
public function checkAllHashes()
|
93 |
{
|
94 |
foreach (self::$suppliedBinariesInfo as $os => $arr) {
|
95 |
-
foreach ($arr as $i => list($filename, $
|
96 |
-
|
97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
}
|
99 |
}
|
100 |
}
|
@@ -427,7 +433,10 @@ class Cwebp extends AbstractConverter
|
|
427 |
} else {
|
428 |
$this->log('. Result: ');
|
429 |
if ($returnCode == 127) {
|
430 |
-
$this->logLn(
|
|
|
|
|
|
|
431 |
} else {
|
432 |
if ($returnCode == 126) {
|
433 |
$this->logLn(
|
55 |
// 2: Set permission to 775. 755 causes unzipping to fail on some hosts
|
56 |
private static $suppliedBinariesInfo = [
|
57 |
'WINNT' => [
|
58 |
+
['cwebp-110-windows-x64.exe', '442682869402f92ad2c8b3186c02b0ea6d6da68d2f908df38bf905b3411eb9fb'],
|
59 |
],
|
60 |
'Darwin' => [
|
61 |
+
['cwebp-110-mac-10_15', 'bfce742da09b959f9f2929ba808fed9ade25c8025530434b6a47d217a6d2ceb5'],
|
62 |
],
|
63 |
'SunOS' => [
|
64 |
// Got this from ewww Wordpress plugin, which unfortunately still uses the old 0.6.0 versions
|
73 |
'Linux' => [
|
74 |
// Dynamically linked executable.
|
75 |
// It seems it is slightly faster than the statically linked
|
76 |
+
['cwebp-110-linux-x86-64', '1603b07b592876dd9fdaa62b44aead800234c9474ff26dc7dd01bc0f4785c9c6'],
|
77 |
|
78 |
// Statically linked executable
|
79 |
// It may be that it on some systems works, where the dynamically linked does not (see #196)
|
89 |
*
|
90 |
* This isn't used when converting, but can be used as a startup check.
|
91 |
*/
|
92 |
+
public static function checkAllHashes()
|
93 |
{
|
94 |
foreach (self::$suppliedBinariesInfo as $os => $arr) {
|
95 |
+
foreach ($arr as $i => list($filename, $expectedHash)) {
|
96 |
+
$actualHash = hash_file("sha256", __DIR__ . '/Binaries/' . $filename);
|
97 |
+
if ($expectedHash != $actualHash) {
|
98 |
+
throw new \Exception(
|
99 |
+
'Hash for ' . $filename . ' is incorrect! ' .
|
100 |
+
'Checksum is: ' . $actualHash . ', ' .
|
101 |
+
', but expected: ' . $expectedHash .
|
102 |
+
'. Did you transfer with FTP, but not in binary mode? '
|
103 |
+
);
|
104 |
}
|
105 |
}
|
106 |
}
|
433 |
} else {
|
434 |
$this->log('. Result: ');
|
435 |
if ($returnCode == 127) {
|
436 |
+
$this->logLn(
|
437 |
+
'*Exec failed* (the cwebp binary was not found at path: ' . $binary .
|
438 |
+
', or it had missing library dependencies)'
|
439 |
+
);
|
440 |
} else {
|
441 |
if ($returnCode == 126) {
|
442 |
$this->logLn(
|
vendor/rosell-dk/webp-convert/src/Convert/Converters/Ewww.php
CHANGED
@@ -34,6 +34,10 @@ class Ewww extends AbstractConverter
|
|
34 |
'auto-filter',
|
35 |
'encoding',
|
36 |
'low-memory',
|
|
|
|
|
|
|
|
|
37 |
'use-nice'
|
38 |
];
|
39 |
}
|
34 |
'auto-filter',
|
35 |
'encoding',
|
36 |
'low-memory',
|
37 |
+
'method',
|
38 |
+
'near-lossless',
|
39 |
+
'preset',
|
40 |
+
'size-in-percentage',
|
41 |
'use-nice'
|
42 |
];
|
43 |
}
|
vendor/rosell-dk/webp-convert/src/Convert/Converters/FFMpeg.php
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPConvert\Convert\Converters;
|
4 |
+
|
5 |
+
use WebPConvert\Convert\Converters\AbstractConverter;
|
6 |
+
use WebPConvert\Convert\Converters\ConverterTraits\ExecTrait;
|
7 |
+
use WebPConvert\Convert\Converters\ConverterTraits\EncodingAutoTrait;
|
8 |
+
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
|
9 |
+
use WebPConvert\Convert\Exceptions\ConversionFailedException;
|
10 |
+
|
11 |
+
//use WebPConvert\Convert\Exceptions\ConversionFailed\InvalidInput\TargetNotFoundException;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Convert images to webp by calling imagemagick binary.
|
15 |
+
*
|
16 |
+
* @package WebPConvert
|
17 |
+
* @author Bjørn Rosell <it@rosell.dk>
|
18 |
+
* @since Class available since Release 2.0.0
|
19 |
+
*/
|
20 |
+
class FFMpeg extends AbstractConverter
|
21 |
+
{
|
22 |
+
use ExecTrait;
|
23 |
+
use EncodingAutoTrait;
|
24 |
+
|
25 |
+
protected function getUnsupportedDefaultOptions()
|
26 |
+
{
|
27 |
+
return [
|
28 |
+
'alpha-quality',
|
29 |
+
'auto-filter',
|
30 |
+
'encoding',
|
31 |
+
'low-memory',
|
32 |
+
'near-lossless',
|
33 |
+
'preset',
|
34 |
+
'size-in-percentage',
|
35 |
+
'use-nice'
|
36 |
+
];
|
37 |
+
}
|
38 |
+
|
39 |
+
private function getPath()
|
40 |
+
{
|
41 |
+
if (defined('WEBPCONVERT_FFMPEG_PATH')) {
|
42 |
+
return constant('WEBPCONVERT_FFMPEG_PATH');
|
43 |
+
}
|
44 |
+
if (!empty(getenv('WEBPCONVERT_FFMPEG_PATH'))) {
|
45 |
+
return getenv('WEBPCONVERT_FFMPEG_PATH');
|
46 |
+
}
|
47 |
+
return 'ffmpeg';
|
48 |
+
}
|
49 |
+
|
50 |
+
public function isInstalled()
|
51 |
+
{
|
52 |
+
exec($this->getPath() . ' -version 2>&1', $output, $returnCode);
|
53 |
+
return ($returnCode == 0);
|
54 |
+
}
|
55 |
+
|
56 |
+
// Check if webp delegate is installed
|
57 |
+
public function isWebPDelegateInstalled()
|
58 |
+
{
|
59 |
+
exec($this->getPath() . ' -version 2>&1', $output, $returnCode);
|
60 |
+
foreach ($output as $line) {
|
61 |
+
if (preg_match('# --enable-libwebp#i', $line)) {
|
62 |
+
return true;
|
63 |
+
}
|
64 |
+
}
|
65 |
+
return false;
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Check (general) operationality of imagack converter executable
|
70 |
+
*
|
71 |
+
* @throws SystemRequirementsNotMetException if system requirements are not met
|
72 |
+
*/
|
73 |
+
public function checkOperationality()
|
74 |
+
{
|
75 |
+
$this->checkOperationalityExecTrait();
|
76 |
+
|
77 |
+
if (!$this->isInstalled()) {
|
78 |
+
throw new SystemRequirementsNotMetException(
|
79 |
+
'ffmpeg is not installed (cannot execute: "' . $this->getPath() . '")'
|
80 |
+
);
|
81 |
+
}
|
82 |
+
if (!$this->isWebPDelegateInstalled()) {
|
83 |
+
throw new SystemRequirementsNotMetException('ffmpeg was compiled without libwebp');
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Build command line options
|
89 |
+
*
|
90 |
+
* @return string
|
91 |
+
*/
|
92 |
+
private function createCommandLineOptions()
|
93 |
+
{
|
94 |
+
// PS: Available webp options for ffmpeg are documented here:
|
95 |
+
// https://www.ffmpeg.org/ffmpeg-codecs.html#libwebp
|
96 |
+
|
97 |
+
$commandArguments = [];
|
98 |
+
|
99 |
+
$commandArguments[] = '-i';
|
100 |
+
$commandArguments[] = escapeshellarg($this->source);
|
101 |
+
|
102 |
+
// preset. Appears first in the list as recommended in the cwebp docs
|
103 |
+
if (!is_null($this->options['preset'])) {
|
104 |
+
if ($this->options['preset'] != 'none') {
|
105 |
+
$commandArguments[] = '-preset ' . $this->options['preset'];
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
// Overwrite existing files?, yes!
|
110 |
+
$commandArguments[] = '-y';
|
111 |
+
|
112 |
+
if ($this->isQualityDetectionRequiredButFailing()) {
|
113 |
+
// quality:auto was specified, but could not be determined.
|
114 |
+
// we cannot apply the max-quality logic, but we can provide auto quality
|
115 |
+
// simply by not specifying the quality option.
|
116 |
+
} else {
|
117 |
+
$commandArguments[] = '-qscale ' . escapeshellarg($this->getCalculatedQuality());
|
118 |
+
}
|
119 |
+
if ($this->options['encoding'] == 'lossless') {
|
120 |
+
$commandArguments[] = '-lossless 1';
|
121 |
+
} else {
|
122 |
+
$commandArguments[] = '-lossless 0';
|
123 |
+
}
|
124 |
+
|
125 |
+
if ($this->options['metadata'] == 'none') {
|
126 |
+
// Unfortunately there seems to be no easy solution available for removing all metadata.
|
127 |
+
}
|
128 |
+
|
129 |
+
// compression_level maps to method, according to https://www.ffmpeg.org/ffmpeg-codecs.html#libwebp
|
130 |
+
$commandArguments[] = '-compression_level ' . $this->options['method'];
|
131 |
+
|
132 |
+
$commandArguments[] = escapeshellarg($this->destination);
|
133 |
+
|
134 |
+
|
135 |
+
return implode(' ', $commandArguments);
|
136 |
+
}
|
137 |
+
|
138 |
+
protected function doActualConvert()
|
139 |
+
{
|
140 |
+
//$this->logLn($this->getVersion());
|
141 |
+
|
142 |
+
$command = $this->getPath() . ' ' . $this->createCommandLineOptions() . ' 2>&1';
|
143 |
+
|
144 |
+
$useNice = (($this->options['use-nice']) && self::hasNiceSupport()) ? true : false;
|
145 |
+
if ($useNice) {
|
146 |
+
$this->logLn('using nice');
|
147 |
+
$command = 'nice ' . $command;
|
148 |
+
}
|
149 |
+
$this->logLn('Executing command: ' . $command);
|
150 |
+
exec($command, $output, $returnCode);
|
151 |
+
|
152 |
+
$this->logExecOutput($output);
|
153 |
+
if ($returnCode == 0) {
|
154 |
+
$this->logLn('success');
|
155 |
+
} else {
|
156 |
+
$this->logLn('return code: ' . $returnCode);
|
157 |
+
}
|
158 |
+
|
159 |
+
if ($returnCode == 127) {
|
160 |
+
throw new SystemRequirementsNotMetException('ffmpeg is not installed');
|
161 |
+
}
|
162 |
+
if ($returnCode != 0) {
|
163 |
+
throw new SystemRequirementsNotMetException('The exec call failed');
|
164 |
+
}
|
165 |
+
}
|
166 |
+
}
|
vendor/rosell-dk/webp-convert/src/Convert/Converters/GraphicsMagick.php
CHANGED
@@ -97,10 +97,18 @@ class GraphicsMagick extends AbstractConverter
|
|
97 |
{
|
98 |
$commandArguments = [];
|
99 |
|
100 |
-
|
101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
$commandArguments[] = '-quality ' . escapeshellarg($this->getCalculatedQuality());
|
103 |
|
|
|
104 |
// encoding
|
105 |
if ($this->options['encoding'] == 'lossless') {
|
106 |
// Btw:
|
97 |
{
|
98 |
$commandArguments = [];
|
99 |
|
100 |
+
/*
|
101 |
+
if ($this->isQualityDetectionRequiredButFailing()) {
|
102 |
+
// Unlike imagick binary, it seems gmagick binary uses a fixed
|
103 |
+
// quality (75) when quality is omitted
|
104 |
+
// So we cannot simply omit in order to get same quality as source.
|
105 |
+
// But perhaps there is another way?
|
106 |
+
// Check out #91 - it is perhaps as easy as this: "-define jpeg:preserve-settings"
|
107 |
+
}
|
108 |
+
*/
|
109 |
$commandArguments[] = '-quality ' . escapeshellarg($this->getCalculatedQuality());
|
110 |
|
111 |
+
|
112 |
// encoding
|
113 |
if ($this->options['encoding'] == 'lossless') {
|
114 |
// Btw:
|
vendor/rosell-dk/webp-convert/src/Convert/Converters/ImageMagick.php
CHANGED
@@ -64,7 +64,7 @@ class ImageMagick extends AbstractConverter
|
|
64 |
// Check if webp delegate is installed
|
65 |
public function isWebPDelegateInstalled()
|
66 |
{
|
67 |
-
exec('
|
68 |
foreach ($output as $line) {
|
69 |
if (preg_match('#webp\\s*=#i', $line)) {
|
70 |
return true;
|
@@ -72,7 +72,7 @@ class ImageMagick extends AbstractConverter
|
|
72 |
}
|
73 |
|
74 |
// try other command
|
75 |
-
exec('
|
76 |
foreach ($output as $line) {
|
77 |
if (preg_match('#DELEGATE.*webp#i', $line)) {
|
78 |
return true;
|
64 |
// Check if webp delegate is installed
|
65 |
public function isWebPDelegateInstalled()
|
66 |
{
|
67 |
+
exec($this->getPath() . ' -list delegate 2>&1', $output, $returnCode);
|
68 |
foreach ($output as $line) {
|
69 |
if (preg_match('#webp\\s*=#i', $line)) {
|
70 |
return true;
|
72 |
}
|
73 |
|
74 |
// try other command
|
75 |
+
exec($this->getPath() . ' -list configure 2>&1', $output, $returnCode);
|
76 |
foreach ($output as $line) {
|
77 |
if (preg_match('#DELEGATE.*webp#i', $line)) {
|
78 |
return true;
|
vendor/rosell-dk/webp-convert/src/Convert/Converters/Imagick.php
CHANGED
@@ -123,8 +123,20 @@ class Imagick extends AbstractConverter
|
|
123 |
}
|
124 |
|
125 |
if ($options['metadata'] == 'none') {
|
126 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
$im->stripImage();
|
|
|
|
|
|
|
|
|
|
|
128 |
}
|
129 |
|
130 |
if ($this->isQualityDetectionRequiredButFailing()) {
|
123 |
}
|
124 |
|
125 |
if ($options['metadata'] == 'none') {
|
126 |
+
// To strip metadata, we need to use the stripImage() method. However, that method does not only remove
|
127 |
+
// metadata, but color profiles as well. We want to keep the color profiles, so we grab it now to be able
|
128 |
+
// to restore it. (Thanks, Max Eremin: https://www.php.net/manual/en/imagick.stripimage.php#120380)
|
129 |
+
|
130 |
+
// Grab color profile (to be able to restore them)
|
131 |
+
$profiles = $im->getImageProfiles("icc", true);
|
132 |
+
|
133 |
+
// Strip metadata (and color profiles)
|
134 |
$im->stripImage();
|
135 |
+
|
136 |
+
// Restore color profiles
|
137 |
+
if (!empty($profiles)) {
|
138 |
+
$im->profileImage("icc", $profiles['icc']);
|
139 |
+
}
|
140 |
}
|
141 |
|
142 |
if ($this->isQualityDetectionRequiredButFailing()) {
|
vendor/rosell-dk/webp-convert/src/Convert/Converters/Stack.php
CHANGED
@@ -66,7 +66,7 @@ class Stack extends AbstractConverter
|
|
66 |
public static function getAvailableConverters()
|
67 |
{
|
68 |
return [
|
69 |
-
'cwebp', 'vips', 'imagick', 'gmagick', 'imagemagick', 'graphicsmagick', 'wpc', 'ewww', 'gd'
|
70 |
];
|
71 |
}
|
72 |
|
@@ -134,8 +134,12 @@ class Stack extends AbstractConverter
|
|
134 |
$defaultConverterOptions = [];
|
135 |
|
136 |
foreach ($this->options2->getOptionsMap() as $id => $option) {
|
137 |
-
|
138 |
-
|
|
|
|
|
|
|
|
|
139 |
$defaultConverterOptions[$id] = $option->getValue();
|
140 |
}
|
141 |
}
|
66 |
public static function getAvailableConverters()
|
67 |
{
|
68 |
return [
|
69 |
+
'cwebp', 'vips', 'imagick', 'gmagick', 'imagemagick', 'graphicsmagick', 'wpc', 'ffmpeg', 'ewww', 'gd'
|
70 |
];
|
71 |
}
|
72 |
|
134 |
$defaultConverterOptions = [];
|
135 |
|
136 |
foreach ($this->options2->getOptionsMap() as $id => $option) {
|
137 |
+
// Right here, there used to be a check that ensured that unknown options was not passed down to the
|
138 |
+
// converters (" && !($option instanceof GhostOption)"). But well, as the Stack doesn't know about
|
139 |
+
// converter specific options, such as "try-cwebp", these was not passed down (see #259)
|
140 |
+
// I'm not sure why the check was made in the first place, but it does not seem neccessary, as the
|
141 |
+
// converters simply ignore unknown options. So the check has now been removed.
|
142 |
+
if ($option->isValueExplicitlySet()) {
|
143 |
$defaultConverterOptions[$id] = $option->getValue();
|
144 |
}
|
145 |
}
|
vendor/rosell-dk/webp-convert/src/Helpers/SanityCheck.txt
ADDED
@@ -0,0 +1,255 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPConvert\Helpers;
|
4 |
+
|
5 |
+
use WebPConvert\Helpers\Sanitize;
|
6 |
+
use WebPConvert\Exceptions\SanityException;
|
7 |
+
|
8 |
+
class SanityCheck
|
9 |
+
{
|
10 |
+
|
11 |
+
/**
|
12 |
+
*
|
13 |
+
* @param string $input string to test for NUL char
|
14 |
+
*/
|
15 |
+
public static function mustBeString($input, $errorMsg = 'String expected')
|
16 |
+
{
|
17 |
+
if (gettype($input) !== 'string') {
|
18 |
+
throw new SanityException($errorMsg);
|
19 |
+
}
|
20 |
+
return $input;
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* The NUL character is a demon, because it can be used to bypass other tests
|
25 |
+
* See https://st-g.de/2011/04/doing-filename-checks-securely-in-PHP.
|
26 |
+
*
|
27 |
+
* @param string $input string to test for NUL char
|
28 |
+
*/
|
29 |
+
public static function noNUL($input, $errorMsg = 'NUL character is not allowed')
|
30 |
+
{
|
31 |
+
self::mustBeString($input);
|
32 |
+
if (strpos($input, chr(0)) !== false) {
|
33 |
+
throw new SanityException($errorMsg);
|
34 |
+
}
|
35 |
+
return $input;
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Prevent control chararters (#00 - #20).
|
40 |
+
*
|
41 |
+
* This prevents line feed, new line, tab, charater return, tab, ets.
|
42 |
+
* https://www.rapidtables.com/code/text/ascii-table.html
|
43 |
+
*
|
44 |
+
* @param string $input string to test for control characters
|
45 |
+
*/
|
46 |
+
public static function noControlChars($input)
|
47 |
+
{
|
48 |
+
self::mustBeString($input);
|
49 |
+
self::noNUL($input);
|
50 |
+
if (preg_match('#[\x{0}-\x{1f}]#', $input)) {
|
51 |
+
throw new SanityException('Control characters are not allowed');
|
52 |
+
}
|
53 |
+
return $input;
|
54 |
+
}
|
55 |
+
|
56 |
+
|
57 |
+
/**
|
58 |
+
*
|
59 |
+
* @param mixed $input something that may not be empty
|
60 |
+
*/
|
61 |
+
public static function notEmpty($input, $errorMsg = 'Must be non-empty')
|
62 |
+
{
|
63 |
+
if (empty($input)) {
|
64 |
+
throw new SanityException($input);
|
65 |
+
}
|
66 |
+
return $input;
|
67 |
+
}
|
68 |
+
|
69 |
+
|
70 |
+
|
71 |
+
public static function noDirectoryTraversal($input, $errorMsg = 'Directory traversal is not allowed')
|
72 |
+
{
|
73 |
+
self::mustBeString($input);
|
74 |
+
self::noControlChars($input);
|
75 |
+
if (preg_match('#\.\.\/#', $input)) {
|
76 |
+
throw new SanityException($errorMsg);
|
77 |
+
}
|
78 |
+
return $input;
|
79 |
+
}
|
80 |
+
|
81 |
+
public static function noStreamWrappers($input, $errorMsg = 'Stream wrappers are not allowed')
|
82 |
+
{
|
83 |
+
self::mustBeString($input);
|
84 |
+
self::noControlChars($input);
|
85 |
+
|
86 |
+
// Prevent stream wrappers ("phar://", "php://" and the like)
|
87 |
+
// https://www.php.net/manual/en/wrappers.phar.php
|
88 |
+
if (preg_match('#^\\w+://#', Sanitize::removeNUL($input))) {
|
89 |
+
throw new SanityException($errorMsg);
|
90 |
+
}
|
91 |
+
return $input;
|
92 |
+
}
|
93 |
+
|
94 |
+
public static function path($input)
|
95 |
+
{
|
96 |
+
self::notEmpty($input);
|
97 |
+
self::mustBeString($input);
|
98 |
+
self::noControlChars($input);
|
99 |
+
self::noDirectoryTraversal($input);
|
100 |
+
self::noStreamWrappers($input);
|
101 |
+
return $input;
|
102 |
+
}
|
103 |
+
|
104 |
+
public static function pathWithoutDirectoryTraversal($input)
|
105 |
+
{
|
106 |
+
return self::path($input);
|
107 |
+
}
|
108 |
+
|
109 |
+
public static function absPathMicrosoftStyle($input, $errorMsg = 'Not an fully qualified Windows path')
|
110 |
+
{
|
111 |
+
// On microsoft we allow [drive letter]:\
|
112 |
+
if (!preg_match("#^[A-Z]:\\\\|/#", $input)) {
|
113 |
+
throw new SanityException($errorMsg . ':' . $input);
|
114 |
+
}
|
115 |
+
return $input;
|
116 |
+
}
|
117 |
+
|
118 |
+
public static function absPath($input, $errorMsg = 'Not an absolute path')
|
119 |
+
{
|
120 |
+
if ((strpos($input, '/') !== 0)) {
|
121 |
+
|
122 |
+
// Check if we are on Microsoft
|
123 |
+
$onMicrosoft = false;
|
124 |
+
if (isset($_SERVER['SERVER_SOFTWARE'])) {
|
125 |
+
if (strpos(strtolower($_SERVER['SERVER_SOFTWARE']), 'microsoft') !== false) {
|
126 |
+
$onMicrosoft = true;
|
127 |
+
}
|
128 |
+
}
|
129 |
+
switch (PHP_OS) {
|
130 |
+
case "WINNT":
|
131 |
+
case "WIN32":
|
132 |
+
case "INTERIX":
|
133 |
+
case "UWIN":
|
134 |
+
case "UWIN-W7":
|
135 |
+
$onMicrosoft = true;
|
136 |
+
break;
|
137 |
+
}
|
138 |
+
|
139 |
+
if (!$onMicrosoft) {
|
140 |
+
throw new SanityException($errorMsg . ':' . $input);
|
141 |
+
}
|
142 |
+
self::absPathMicrosoftStyle($input);
|
143 |
+
|
144 |
+
}
|
145 |
+
return self::path($input);
|
146 |
+
}
|
147 |
+
|
148 |
+
public static function pathBeginsWith($input, $beginsWith, $errorMsg = 'Path is outside allowed path')
|
149 |
+
{
|
150 |
+
self::path($input);
|
151 |
+
if (!(strpos($input, $beginsWith) === 0)) {
|
152 |
+
throw new SanityException($errorMsg);
|
153 |
+
}
|
154 |
+
return $input;
|
155 |
+
}
|
156 |
+
|
157 |
+
public static function findClosestExistingFolderSymLinksExpanded($input) {
|
158 |
+
$levelsUp = 1;
|
159 |
+
//echo 'input:' . $input;
|
160 |
+
while (true) {
|
161 |
+
$dir = dirname($input, $levelsUp);
|
162 |
+
//echo 'dir:' . $dir . '<br>';
|
163 |
+
$realPathResult = realpath($dir);
|
164 |
+
if ($realPathResult !== false) {
|
165 |
+
return $realPathResult;
|
166 |
+
}
|
167 |
+
if (($dir == '/') || (strlen($dir) < 4)) {
|
168 |
+
return $dir;
|
169 |
+
}
|
170 |
+
$levelsUp++;
|
171 |
+
}
|
172 |
+
return '/';
|
173 |
+
}
|
174 |
+
|
175 |
+
public static function pathBeginsWithSymLinksExpanded($input, $beginsWith, $errorMsg = 'Path is outside allowed path') {
|
176 |
+
$closestExistingFolder = self::findClosestExistingFolderSymLinksExpanded($input);
|
177 |
+
//throw new SanityException('hm.' . $input . ' : <br>' . $closestExistingFolder);
|
178 |
+
self::pathBeginsWith($closestExistingFolder, $beginsWith, $errorMsg);
|
179 |
+
}
|
180 |
+
|
181 |
+
|
182 |
+
|
183 |
+
public static function absPathExists($input, $errorMsg = 'Path does not exist')
|
184 |
+
{
|
185 |
+
self::absPath($input);
|
186 |
+
if (@!file_exists($input)) {
|
187 |
+
throw new SanityException($errorMsg);
|
188 |
+
}
|
189 |
+
return $input;
|
190 |
+
}
|
191 |
+
|
192 |
+
public static function absPathExistsAndIsDir(
|
193 |
+
$input,
|
194 |
+
$errorMsg = 'Path points to a file (it should point to a directory)'
|
195 |
+
) {
|
196 |
+
self::absPathExists($input);
|
197 |
+
if (!is_dir($input)) {
|
198 |
+
throw new SanityException($errorMsg);
|
199 |
+
}
|
200 |
+
return $input;
|
201 |
+
}
|
202 |
+
|
203 |
+
public static function absPathExistsAndIsFile(
|
204 |
+
$input,
|
205 |
+
$errorMsg = 'Path points to a directory (it should not do that)'
|
206 |
+
) {
|
207 |
+
self::absPathExists($input, 'File does not exist');
|
208 |
+
if (@is_dir($input)) {
|
209 |
+
throw new SanityException($errorMsg);
|
210 |
+
}
|
211 |
+
return $input;
|
212 |
+
}
|
213 |
+
|
214 |
+
public static function absPathExistsAndIsNotDir(
|
215 |
+
$input,
|
216 |
+
$errorMsg = 'Path points to a directory (it should point to a file)'
|
217 |
+
) {
|
218 |
+
self::absPathExistsAndIsFile($input, $errorMsg);
|
219 |
+
return $input;
|
220 |
+
}
|
221 |
+
|
222 |
+
|
223 |
+
public static function pregMatch($pattern, $input, $errorMsg = 'Does not match expected pattern')
|
224 |
+
{
|
225 |
+
self::noNUL($input);
|
226 |
+
self::mustBeString($input);
|
227 |
+
if (!preg_match($pattern, $input)) {
|
228 |
+
throw new SanityException($errorMsg);
|
229 |
+
}
|
230 |
+
return $input;
|
231 |
+
}
|
232 |
+
|
233 |
+
public static function isJSONArray($input, $errorMsg = 'Not a JSON array')
|
234 |
+
{
|
235 |
+
self::noNUL($input);
|
236 |
+
self::mustBeString($input);
|
237 |
+
self::notEmpty($input);
|
238 |
+
if ((strpos($input, '[') !== 0) || (!is_array(json_decode($input)))) {
|
239 |
+
throw new SanityException($errorMsg);
|
240 |
+
}
|
241 |
+
return $input;
|
242 |
+
}
|
243 |
+
|
244 |
+
public static function isJSONObject($input, $errorMsg = 'Not a JSON object')
|
245 |
+
{
|
246 |
+
self::noNUL($input);
|
247 |
+
self::mustBeString($input);
|
248 |
+
self::notEmpty($input);
|
249 |
+
if ((strpos($input, '{') !== 0) || (!is_object(json_decode($input)))) {
|
250 |
+
throw new SanityException($errorMsg);
|
251 |
+
}
|
252 |
+
return $input;
|
253 |
+
}
|
254 |
+
|
255 |
+
}
|
webp-express.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
* Plugin Name: WebP Express
|
4 |
* Plugin URI: https://github.com/rosell-dk/webp-express
|
5 |
* Description: Serve autogenerated WebP images instead of jpeg/png to browsers that supports WebP. Works on anything (media library images, galleries, theme images etc).
|
6 |
-
* Version: 0.
|
7 |
* Author: Bjørn Rosell
|
8 |
* Author URI: https://www.bitwise-it.dk
|
9 |
* License: GPL2
|
@@ -14,10 +14,9 @@
|
|
14 |
Note: Perhaps create a plugin page on my website?, ie https://www.bitwise-it.dk/software/wordpress/webp-express
|
15 |
*/
|
16 |
|
17 |
-
if (
|
18 |
|
19 |
-
|
20 |
-
use \WebPExpress\Option;
|
21 |
|
22 |
define('WEBPEXPRESS_PLUGIN', __FILE__);
|
23 |
define('WEBPEXPRESS_PLUGIN_DIR', __DIR__);
|
@@ -47,7 +46,7 @@ function webp_express_process_post() {
|
|
47 |
add_action( 'init', 'webp_express_process_post' );
|
48 |
//add_action( 'parse_request', 'webp_express_process_post' );
|
49 |
|
50 |
-
if (Option::getOption('webp-express-alter-html', false)) {
|
51 |
require_once __DIR__ . '/lib/classes/AlterHtmlInit.php';
|
52 |
\WebPExpress\AlterHtmlInit::setHooks();
|
53 |
}
|
3 |
* Plugin Name: WebP Express
|
4 |
* Plugin URI: https://github.com/rosell-dk/webp-express
|
5 |
* Description: Serve autogenerated WebP images instead of jpeg/png to browsers that supports WebP. Works on anything (media library images, galleries, theme images etc).
|
6 |
+
* Version: 0.19.0
|
7 |
* Author: Bjørn Rosell
|
8 |
* Author URI: https://www.bitwise-it.dk
|
9 |
* License: GPL2
|
14 |
Note: Perhaps create a plugin page on my website?, ie https://www.bitwise-it.dk/software/wordpress/webp-express
|
15 |
*/
|
16 |
|
17 |
+
if (!defined('ABSPATH')) exit; // Exit if accessed directly
|
18 |
|
19 |
+
if (defined('WEBPEXPRESS_PLUGIN')) exit; // Prevent problems if plugin is included twice (#472)
|
|
|
20 |
|
21 |
define('WEBPEXPRESS_PLUGIN', __FILE__);
|
22 |
define('WEBPEXPRESS_PLUGIN_DIR', __DIR__);
|
46 |
add_action( 'init', 'webp_express_process_post' );
|
47 |
//add_action( 'parse_request', 'webp_express_process_post' );
|
48 |
|
49 |
+
if (\WebPExpress\Option::getOption('webp-express-alter-html', false)) {
|
50 |
require_once __DIR__ . '/lib/classes/AlterHtmlInit.php';
|
51 |
\WebPExpress\AlterHtmlInit::setHooks();
|
52 |
}
|