Version Description
This version added option for setting caching header, fixed a serious issue with Imagick, added a new converter, Gmagick, added a great deal of options to Cwebp and generally improved the interface.
- Added option for caching
- Fixed long standing and serious issue with Imagick converter. It no longer generates webp images in poor quality
- Added gmagick as a new conversion method
- WebPExpress now runs on newly released WebP-Convert 1.2.0
- Added many new options for cwebp
- You can now quickly see converter status by hovering over a converter
- You can now choose between having quality auto-detected or not (if the server supports detecting quality).
- If the server does not support detecting quality, the WPC converter will display a quality "auto" option
- Added special intro message for those who has no working conversion methods
- Added help texts for options
- Settings are now saved, when changing converter options. Too many times, I found myself forgetting to save...
For more info, see the closed issues on the 0.6.0 milestone on our github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.6.0
=
Download this release
Release Info
Developer | rosell.dk |
Plugin | WebP Express |
Version | 0.6.0 |
Comparing to | |
See all releases |
Code changes from version 0.5.0 to 0.6.0
- .gitignore +3 -0
- README.md +26 -30
- README.txt +27 -33
- changelog.txt +24 -0
- composer.json +12 -0
- lib/activate-first-time.php +4 -1
- lib/admin.php +1 -1
- lib/classes/Config.php +45 -1
- lib/classes/ConvertersHelper.php +63 -0
- lib/classes/Paths.php +14 -0
- lib/classes/TestRun.php +94 -0
- lib/migrate/migrate.php +1 -4
- lib/migrate/migrate1.php +2 -2
- lib/migrate/migrate2.php +71 -0
- lib/options/css/webp-express-options-page.css +123 -15
- lib/options/enqueue_scripts.php +2 -2
- lib/options/js/webp-express-options-page.js +149 -31
- lib/options/options-hooks.php +1 -1
- lib/options/page-messages.php +2 -0
- lib/options/page-welcome.php +31 -5
- lib/options/page.php +330 -73
- lib/options/submit.php +28 -3
- lib/reactivate.php +8 -3
- test/small-q61.jpg +0 -0
- test/test-run.php +11 -17
- webp-express.php +1 -1
- wod/Binaries/cwebp-fbsd +0 -0
- wod/Binaries/cwebp-linux +0 -0
- wod/Binaries/cwebp-mac12 +0 -0
- wod/Binaries/cwebp-sol +0 -0
- wod/Binaries/cwebp.exe +0 -0
- wod/webp-convert-and-serve.inc +0 -1615
- wod/webp-on-demand.inc +0 -135
- wod/webp-on-demand.php +24 -4
.gitignore
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
1 |
+
composer.lock
|
2 |
+
composer.phar
|
3 |
+
/vendor
|
README.md
CHANGED
@@ -2,16 +2,18 @@
|
|
2 |
|
3 |
Serve autogenerated WebP images instead of jpeg/png to browsers that supports WebP. Works on anything (media library, galleries, theme images etc).
|
4 |
|
|
|
|
|
5 |
## Description
|
6 |
|
7 |
This plugin let's you take advantage of the WebP image format with only a little effort. Install, configure, test, forget - and enjoy the increased performance of your website.
|
8 |
|
9 |
The plugin basically routes jpeg/png images to an image converter, or - if the image converter has already converted the image - directly to a converted image. The approach has the benefit that is works regardless of how an image found its way into your server - be it Media Library, Galleries, or even theme images referenced with CSS.
|
10 |
|
11 |
-
The plugin builds on [WebPConvert](https://github.com/rosell-dk/webp-convert) and
|
12 |
|
13 |
#### Benefits
|
14 |
-
- Much faster load time
|
15 |
- Better user experience (whether performance goes from terrible to bad, or from good to impressive, it is a benefit)
|
16 |
- Better ranking in Google searches (performance is taken into account by Google)
|
17 |
- Less bandwidth consumption - makes a difference when abroad and in the parts of the world with slow and expensive internet connections.
|
@@ -47,20 +49,20 @@ Note that the plugin does not change any HTML. In the HTML the image src is stil
|
|
47 |
- Reload the page
|
48 |
- Find a jpeg or png image in the list. In the "type" column, it should say "webp"
|
49 |
|
50 |
-
In order to test that the image is not being reconverted every time, look at the Response headers of the image. There should be a "X-WebP-
|
51 |
|
52 |
-
You can also append `?debug` after any image url, in order to run a conversion, and see the conversion report.
|
53 |
|
54 |
### Notes
|
55 |
|
56 |
*Note:*
|
57 |
-
The redirect rules created in *.htaccess* are pointing to
|
58 |
|
59 |
*Note:*
|
60 |
Do not simply remove the plugin without deactivating it first. Deactivation takes care of removing the rules in the *.htaccess* file. With the rules there, but converter gone, your Google Chrome visitors will not see any jpeg images.
|
61 |
|
62 |
*Note:*
|
63 |
-
The plugin has not been tested in multisite configurations. It's on the roadmap
|
64 |
|
65 |
|
66 |
## Limitations
|
@@ -71,8 +73,8 @@ The plugin has not been tested in multisite configurations. It's on the roadmap!
|
|
71 |
|
72 |
## Frequently Asked Questions
|
73 |
|
74 |
-
###
|
75 |
-
|
76 |
|
77 |
### How do I make this work with a CDN?
|
78 |
Chances are that the default setting of your CDN is not to forward any headers to your origin server. But the plugin needs the "Accept" header, because this is where the information is whether the browser accepts webp images or not. You will therefore have to make sure to configure your CDN to forward the "Accept" header.
|
@@ -82,28 +84,22 @@ The plugin takes care of setting the "Vary" HTTP header to "Accept" when routing
|
|
82 |
### How do I donate?
|
83 |
Putting this question in the "frequently" asked questions section is of course some mixture of humour, sarcasm and wishful thinking. In case there really is someone out there wanting to donate, you can simply write to me, and we can arrange. My contact information is available here https://www.bitwise-it.dk/contact. I have paypal and of course an ordinary bank account.
|
84 |
|
85 |
-
## Changes in 0.
|
86 |
-
This version
|
87 |
-
|
88 |
-
*
|
89 |
-
*
|
90 |
-
*
|
91 |
-
*
|
92 |
-
*
|
93 |
-
*
|
94 |
-
*
|
95 |
-
*
|
96 |
-
*
|
97 |
-
*
|
98 |
-
*
|
99 |
-
|
100 |
-
|
101 |
-
* Denies deactivation if rewrite rules could not be removed
|
102 |
-
* Refactored thoroughly
|
103 |
-
* More helpful texts.
|
104 |
-
* Extensive testing. Tested on Wordpress 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8 and 4.9. Tested with PHP 5.6, PHP 7.0 and PHP 7.1. Tested on Apache and LiteSpeed. Tested when missing various write permissions. Tested migration. Tested when installed in root, in subfolder, when Wordpress has its own directory (both methods), when wp-content is moved out of Wordpress directory, when plugins is moved out of Wordpress directory, when both of them are moved and when uploads have been moved.
|
105 |
-
|
106 |
-
For more info, see the closed issues on the 0.5.0 milestone on our github repository: https://github.com/rosell-dk/webp-express/milestone/2?closed=1
|
107 |
|
108 |
# Roadmap
|
109 |
|
2 |
|
3 |
Serve autogenerated WebP images instead of jpeg/png to browsers that supports WebP. Works on anything (media library, galleries, theme images etc).
|
4 |
|
5 |
+
The plugin is available on the Wordpress codex ([here](https://wordpress.org/plugins/webp-express/)), and developed on github ([here](https://github.com/rosell-dk/webp-express/)).
|
6 |
+
|
7 |
## Description
|
8 |
|
9 |
This plugin let's you take advantage of the WebP image format with only a little effort. Install, configure, test, forget - and enjoy the increased performance of your website.
|
10 |
|
11 |
The plugin basically routes jpeg/png images to an image converter, or - if the image converter has already converted the image - directly to a converted image. The approach has the benefit that is works regardless of how an image found its way into your server - be it Media Library, Galleries, or even theme images referenced with CSS.
|
12 |
|
13 |
+
The plugin builds on [WebPConvert](https://github.com/rosell-dk/webp-convert) and its "WebP On Demand" solution described [here](https://github.com/rosell-dk/webp-convert/blob/master/docs/webp-on-demand/webp-on-demand.md)
|
14 |
|
15 |
#### Benefits
|
16 |
+
- Much faster load time for images in blink based browsers such as Chrome and Opera (accounting for ~73% of all traffic, according to [caniuse.com](https://caniuse.com/webp)). The converted images are typically *less than half the size* (for jpeg), while maintaining the same quality. Bear in mind that for most web sites, images are responsible for the largest part of the waiting time.
|
17 |
- Better user experience (whether performance goes from terrible to bad, or from good to impressive, it is a benefit)
|
18 |
- Better ranking in Google searches (performance is taken into account by Google)
|
19 |
- Less bandwidth consumption - makes a difference when abroad and in the parts of the world with slow and expensive internet connections.
|
49 |
- Reload the page
|
50 |
- Find a jpeg or png image in the list. In the "type" column, it should say "webp"
|
51 |
|
52 |
+
In order to test that the image is not being reconverted every time, look at the Response headers of the image. There should be a "X-WebP-Convert-Status" header. It should say "Serving existing converted image" the first time, but "Serving existing converted image" on subsequent requests (WebP-Express is based upon [WebP Convert](https://github.com/rosell-dk/webp-convert)).
|
53 |
|
54 |
+
You can also append `?debug` after any image url, in order to run a conversion, and see the conversion report. Also, if you append `?reconvert` after an image url, you will force a reconversion of the image.
|
55 |
|
56 |
### Notes
|
57 |
|
58 |
*Note:*
|
59 |
+
The redirect rules created in *.htaccess* are pointing to a PHP script. If you happen to change the url path of your plugins, the rules will have to be updated. The *.htaccess* also passes the path to wp-content (relative to document root) to the script, so the script knows where to find its configuration and where to store converted images. So again, if you move the wp-content folder, or perhaps moves Wordpress to a subfolder, the rules will have to be updated. As moving these things around is is a rare situation, WebP Express are not using any resources monitoring this. However, it will do the check when you visit the settings page.
|
60 |
|
61 |
*Note:*
|
62 |
Do not simply remove the plugin without deactivating it first. Deactivation takes care of removing the rules in the *.htaccess* file. With the rules there, but converter gone, your Google Chrome visitors will not see any jpeg images.
|
63 |
|
64 |
*Note:*
|
65 |
+
The plugin has not been tested in multisite configurations. It's on the roadmap...
|
66 |
|
67 |
|
68 |
## Limitations
|
73 |
|
74 |
## Frequently Asked Questions
|
75 |
|
76 |
+
### Why do I not see the option to set WebP quality to auto?
|
77 |
+
The option will only display, if your system is able to detect jpeg qualities. To make your server capable to do that, install *Imagick* or *Gmagick*
|
78 |
|
79 |
### How do I make this work with a CDN?
|
80 |
Chances are that the default setting of your CDN is not to forward any headers to your origin server. But the plugin needs the "Accept" header, because this is where the information is whether the browser accepts webp images or not. You will therefore have to make sure to configure your CDN to forward the "Accept" header.
|
84 |
### How do I donate?
|
85 |
Putting this question in the "frequently" asked questions section is of course some mixture of humour, sarcasm and wishful thinking. In case there really is someone out there wanting to donate, you can simply write to me, and we can arrange. My contact information is available here https://www.bitwise-it.dk/contact. I have paypal and of course an ordinary bank account.
|
86 |
|
87 |
+
## Changes in 0.6.0
|
88 |
+
This version added option for setting caching header, fixed a serious issue with *Imagick*, added a new converter, *Gmagick*, added a great deal of options to *Cwebp* and generally improved the interface.
|
89 |
+
|
90 |
+
* Added option for caching
|
91 |
+
* Fixed long standing and serious issue with Imagick converter. It no longer generates webp images in poor quality
|
92 |
+
* Added gmagick as a new conversion method
|
93 |
+
* WebPExpress now runs on newly released WebP-Convert 1.2.0
|
94 |
+
* Added many new options for *cwebp*
|
95 |
+
* You can now quickly see converter status by hovering over a converter
|
96 |
+
* You can now choose between having quality auto-detected or not (if the server supports detecting quality).
|
97 |
+
* If the server does not support detecting quality, the WPC converter will display a quality "auto" option
|
98 |
+
* Added special intro message for those who has no working conversion methods
|
99 |
+
* Added help texts for options
|
100 |
+
* Settings are now saved, when changing converter options. Too many times, I found myself forgetting to save...
|
101 |
+
|
102 |
+
For more info, see the closed issues on the 0.6.0 milestone on our github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.6.0
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
|
104 |
# Roadmap
|
105 |
|
README.txt
CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.bitwise-it.dk/contact
|
|
4 |
Tags: webp, images, performance
|
5 |
Requires at least: 4.0
|
6 |
Tested up to: 4.9
|
7 |
-
Stable tag: 0.
|
8 |
Requires PHP: 5.6
|
9 |
License: GPLv3
|
10 |
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
@@ -17,10 +17,10 @@ This plugin let's you take advantage of the WebP image format with only a little
|
|
17 |
|
18 |
The plugin basically routes jpeg/png images to an image converter, or - if the image converter has already converted the image - directly to a converted image. The approach has the benefit that is works regardless of how an image found its way into your server - be it Media Library, Galleries, or even theme images referenced with CSS.
|
19 |
|
20 |
-
The plugin builds on [WebPConvert](https://github.com/rosell-dk/webp-convert) and
|
21 |
|
22 |
#### Benefits
|
23 |
-
- Much faster load time
|
24 |
- Better user experience (whether performance goes from terrible to bad, or from good to impressive, it is a benefit)
|
25 |
- Better ranking in Google searches (performance is taken into account by Google)
|
26 |
- Less bandwidth consumption - makes a difference when abroad and in the parts of the world with slow and expensive internet connections.
|
@@ -57,21 +57,21 @@ Note that the plugin does not change any HTML. In the HTML the image src is stil
|
|
57 |
- Reload the page
|
58 |
- Find a jpeg or png image in the list. In the "type" column, it should say "webp"
|
59 |
|
60 |
-
In order to test that the image is not being reconverted every time, look at the Response headers of the image. There should be a "X-WebP-
|
61 |
|
62 |
You can also append ?debug after any image url, in order to run a conversion, and see the conversion report.
|
63 |
-
|
64 |
|
65 |
### Notes
|
66 |
|
67 |
*Note:*
|
68 |
-
The redirect rules created in *.htaccess* are pointing to
|
69 |
|
70 |
*Note:*
|
71 |
Do not simply remove the plugin without deactivating it first. Deactivation takes care of removing the rules in the *.htaccess* file. With the rules there, but converter gone, your Google Chrome visitors will not see any jpeg images.
|
72 |
|
73 |
*Note:*
|
74 |
-
The plugin has not been tested in multisite configurations. It's on the roadmap
|
75 |
|
76 |
== Limitations ==
|
77 |
|
@@ -81,8 +81,8 @@ The plugin has not been tested in multisite configurations. It's on the roadmap!
|
|
81 |
|
82 |
== Frequently Asked Questions ==
|
83 |
|
84 |
-
=
|
85 |
-
|
86 |
|
87 |
= How do I make this work with a CDN? =
|
88 |
Chances are that the default setting of your CDN is not to forward any headers to your origin server. But the plugin needs the "Accept" header, because this is where the information is whether the browser accepts webp images or not. You will therefore have to make sure to configure your CDN to forward the "Accept" header.
|
@@ -100,33 +100,27 @@ Putting this question in the "frequently" asked questions section is of course s
|
|
100 |
|
101 |
== Changelog ==
|
102 |
|
103 |
-
= 0.
|
104 |
-
This version
|
105 |
-
|
106 |
-
*
|
107 |
-
*
|
108 |
-
*
|
109 |
-
*
|
110 |
-
*
|
111 |
-
*
|
112 |
-
*
|
113 |
-
*
|
114 |
-
*
|
115 |
-
*
|
116 |
-
*
|
117 |
-
|
118 |
-
|
119 |
-
* Denies deactivation if rewrite rules could not be removed
|
120 |
-
* Refactored thoroughly
|
121 |
-
* More helpful texts.
|
122 |
-
* Extensive testing. Tested on Wordpress 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8 and 4.9. Tested with PHP 5.6, PHP 7.0 and PHP 7.1. Tested on Apache and LiteSpeed. Tested when missing various write permissions. Tested migration. Tested when installed in root, in subfolder, when Wordpress has its own directory (both methods), when wp-content is moved out of Wordpress directory, when plugins is moved out of Wordpress directory, when both of them are moved and when uploads have been moved.
|
123 |
-
|
124 |
-
For more info, see the closed issues on the 0.5.0 milestone on our github repository: https://github.com/rosell-dk/webp-express/milestone/2?closed=1
|
125 |
|
126 |
== Upgrade Notice ==
|
127 |
|
128 |
-
= 0.
|
129 |
-
|
130 |
|
131 |
== Roadmap ==
|
132 |
|
4 |
Tags: webp, images, performance
|
5 |
Requires at least: 4.0
|
6 |
Tested up to: 4.9
|
7 |
+
Stable tag: 0.6.0
|
8 |
Requires PHP: 5.6
|
9 |
License: GPLv3
|
10 |
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
17 |
|
18 |
The plugin basically routes jpeg/png images to an image converter, or - if the image converter has already converted the image - directly to a converted image. The approach has the benefit that is works regardless of how an image found its way into your server - be it Media Library, Galleries, or even theme images referenced with CSS.
|
19 |
|
20 |
+
The plugin builds on [WebPConvert](https://github.com/rosell-dk/webp-convert) and its "WebP On Demand" solution described [here](https://github.com/rosell-dk/webp-convert/blob/master/docs/webp-on-demand/webp-on-demand.md)
|
21 |
|
22 |
#### Benefits
|
23 |
+
- Much faster load time for images in blink based browsers such as Chrome and Opera (accounting for ~73% of all traffic, according to [caniuse.com](https://caniuse.com/webp)). The converted images are typically *less than half the size* (for jpeg), while maintaining the same quality. Bear in mind that for most web sites, images are responsible for the largest part of the waiting time.
|
24 |
- Better user experience (whether performance goes from terrible to bad, or from good to impressive, it is a benefit)
|
25 |
- Better ranking in Google searches (performance is taken into account by Google)
|
26 |
- Less bandwidth consumption - makes a difference when abroad and in the parts of the world with slow and expensive internet connections.
|
57 |
- Reload the page
|
58 |
- Find a jpeg or png image in the list. In the "type" column, it should say "webp"
|
59 |
|
60 |
+
In order to test that the image is not being reconverted every time, look at the Response headers of the image. There should be a "X-WebP-Convert-Status" header. It should say "Serving existing converted image" the first time, but "Serving existing converted image" on subsequent requests (WebP-Express is based upon [WebP Convert](https://github.com/rosell-dk/webp-convert)).
|
61 |
|
62 |
You can also append ?debug after any image url, in order to run a conversion, and see the conversion report.
|
63 |
+
Also, you append ?reconvert after an image url, you will force a reconversion of the image.
|
64 |
|
65 |
### Notes
|
66 |
|
67 |
*Note:*
|
68 |
+
The redirect rules created in *.htaccess* are pointing to a PHP script. If you happen to change the url path of your plugins, the rules will have to be updated. The *.htaccess* also passes the path to wp-content (relative to document root) to the script, so the script knows where to find its configuration and where to store converted images. So again, if you move the wp-content folder, or perhaps moves Wordpress to a subfolder, the rules will have to be updated. As moving these things around is is a rare situation, WebP Express are not using any resources monitoring this. However, it will do the check when you visit the settings page.
|
69 |
|
70 |
*Note:*
|
71 |
Do not simply remove the plugin without deactivating it first. Deactivation takes care of removing the rules in the *.htaccess* file. With the rules there, but converter gone, your Google Chrome visitors will not see any jpeg images.
|
72 |
|
73 |
*Note:*
|
74 |
+
The plugin has not been tested in multisite configurations. It's on the roadmap...
|
75 |
|
76 |
== Limitations ==
|
77 |
|
81 |
|
82 |
== Frequently Asked Questions ==
|
83 |
|
84 |
+
= Why do I not see the option to set WebP quality to auto? =
|
85 |
+
The option will only display, if your system is able to detect jpeg qualities. To make your server capable to do that, install *Imagick* or *Gmagick*
|
86 |
|
87 |
= How do I make this work with a CDN? =
|
88 |
Chances are that the default setting of your CDN is not to forward any headers to your origin server. But the plugin needs the "Accept" header, because this is where the information is whether the browser accepts webp images or not. You will therefore have to make sure to configure your CDN to forward the "Accept" header.
|
100 |
|
101 |
== Changelog ==
|
102 |
|
103 |
+
= 0.6.0 =
|
104 |
+
This version added option for setting caching header, fixed a serious issue with *Imagick*, added a new converter, *Gmagick*, added a great deal of options to *Cwebp* and generally improved the interface.
|
105 |
+
|
106 |
+
* Added option for caching
|
107 |
+
* Fixed long standing and serious issue with Imagick converter. It no longer generates webp images in poor quality
|
108 |
+
* Added gmagick as a new conversion method
|
109 |
+
* WebPExpress now runs on newly released WebP-Convert 1.2.0
|
110 |
+
* Added many new options for *cwebp*
|
111 |
+
* You can now quickly see converter status by hovering over a converter
|
112 |
+
* You can now choose between having quality auto-detected or not (if the server supports detecting quality).
|
113 |
+
* If the server does not support detecting quality, the WPC converter will display a quality "auto" option
|
114 |
+
* Added special intro message for those who has no working conversion methods
|
115 |
+
* Added help texts for options
|
116 |
+
* Settings are now saved, when changing converter options. Too many times, I found myself forgetting to save...
|
117 |
+
|
118 |
+
For more info, see the closed issues on the 0.6.0 milestone on our github repository: https://github.com/rosell-dk/webp-express/issues?q=is%3Aclosed+milestone%3A0.6.0
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
|
120 |
== Upgrade Notice ==
|
121 |
|
122 |
+
= 0.6.0 =
|
123 |
+
Adding caching option, fixed imagick converter, added gmagick converter and more!
|
124 |
|
125 |
== Roadmap ==
|
126 |
|
changelog.txt
CHANGED
@@ -1,3 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
= 0.4.0 =
|
2 |
This version fixes some misbehaviours and provides new http headers with info about the conversion process.
|
3 |
|
@@ -7,6 +30,7 @@ This version fixes some misbehaviours and provides new http headers with info ab
|
|
7 |
* WebPExpress options are now removed when plugin is uninstalled.
|
8 |
* No longer generates .htaccess rules on install. The user now has to actively go to Web Express setting and save first
|
9 |
* Added a "first time" message on options page and a reactivation message
|
|
|
10 |
For more info, see the closed issues on the github repository: https://github.com/rosell-dk/webp-express/milestone/1?closed=1
|
11 |
|
12 |
= 0.3.1 =
|
1 |
+
= 0.5.0 =
|
2 |
+
This version works on many more setups than the previous. Also uses less resources and handles when images are changed.
|
3 |
+
|
4 |
+
* Configuration is now stored in a separate configuration file instead of storing directly in the *.htaccess* file and passing it on via query string. When updating, these settings are migrated automatically.
|
5 |
+
* Handles setups where Wordpress has been given its own directory (both methods mentioned [here](https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory))
|
6 |
+
* Handles setups where *wp-content* has been moved, even out of Wordpress root.
|
7 |
+
* Handles setups where Uploads folder has been moved, even out of *wp-content*.
|
8 |
+
* Handles setups where Plugins folder has been moved, even out of *wp-content* or out of Wordpress root
|
9 |
+
* Is not as likely to be subject to firewalls blocking requests (in 0.4.0, we passed all options in a querystring, and that could trigger firewalls under some circumstances)
|
10 |
+
* Is not as likely to be subject to rewrite rules from other plugins interfering. WebP Express now stores the .htaccess in the wp-content folder (if you allow it). As this is deeper than the root folder, the rules in here takes precedence over rules in the main *.htaccess*
|
11 |
+
* The *.htaccess* now passes the complete absulute path to the source file instead of a relative path. This is a less error-prone method.
|
12 |
+
* Reconverts the webp, if source image has changed
|
13 |
+
* Now runs on version 1.0.0 of [WebP On Demand](https://github.com/rosell-dk/webp-on-demand). Previously ran on 0.3.0
|
14 |
+
* Now takes care of only loading the PHP classes when needed in order not to slow down your Wordpress. The frontend will only need to process four lines of code. The backend footprint is also quite small now (80 lines of code of hooks)
|
15 |
+
* Now works in Wordpress 4.0 - 4.6.
|
16 |
+
* Added cache-breaking tokens to image test links
|
17 |
+
* Denies deactivation if rewrite rules could not be removed
|
18 |
+
* Refactored thoroughly
|
19 |
+
* More helpful texts.
|
20 |
+
* Extensive testing. Tested on Wordpress 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8 and 4.9. Tested with PHP 5.6, PHP 7.0 and PHP 7.1. Tested on Apache and LiteSpeed. Tested when missing various write permissions. Tested migration. Tested when installed in root, in subfolder, when Wordpress has its own directory (both methods), when wp-content is moved out of Wordpress directory, when plugins is moved out of Wordpress directory, when both of them are moved and when uploads have been moved.
|
21 |
+
|
22 |
+
For more info, see the closed issues on the 0.5.0 milestone on our github repository: https://github.com/rosell-dk/webp-express/milestone/2?closed=1
|
23 |
+
|
24 |
= 0.4.0 =
|
25 |
This version fixes some misbehaviours and provides new http headers with info about the conversion process.
|
26 |
|
30 |
* WebPExpress options are now removed when plugin is uninstalled.
|
31 |
* No longer generates .htaccess rules on install. The user now has to actively go to Web Express setting and save first
|
32 |
* Added a "first time" message on options page and a reactivation message
|
33 |
+
|
34 |
For more info, see the closed issues on the github repository: https://github.com/rosell-dk/webp-express/milestone/1?closed=1
|
35 |
|
36 |
= 0.3.1 =
|
composer.json
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"minimum-stability": "dev",
|
3 |
+
"repositories": [
|
4 |
+
{
|
5 |
+
"type": "vcs",
|
6 |
+
"url": "https://github.com/rosell-dk/webp-convert"
|
7 |
+
}
|
8 |
+
],
|
9 |
+
"require": {
|
10 |
+
"rosell-dk/webp-convert": "dev-master"
|
11 |
+
}
|
12 |
+
}
|
lib/activate-first-time.php
CHANGED
@@ -9,6 +9,9 @@ use \WebPExpress\Config;
|
|
9 |
include_once __DIR__ . '/classes/Messenger.php';
|
10 |
use \WebPExpress\Messenger;
|
11 |
|
|
|
|
|
|
|
12 |
include_once __DIR__ . '/classes/PlatformInfo.php';
|
13 |
use \WebPExpress\PlatformInfo;
|
14 |
|
@@ -61,5 +64,5 @@ if (PlatformInfo::isApache() || PlatformInfo::isLiteSpeed()) {
|
|
61 |
Messenger::addMessage(
|
62 |
'info',
|
63 |
'WebP Express was installed successfully. To start using it, you must ' .
|
64 |
-
'<a href="
|
65 |
);
|
9 |
include_once __DIR__ . '/classes/Messenger.php';
|
10 |
use \WebPExpress\Messenger;
|
11 |
|
12 |
+
include_once __DIR__ . '/classes/Paths.php';
|
13 |
+
use \WebPExpress\Paths;
|
14 |
+
|
15 |
include_once __DIR__ . '/classes/PlatformInfo.php';
|
16 |
use \WebPExpress\PlatformInfo;
|
17 |
|
64 |
Messenger::addMessage(
|
65 |
'info',
|
66 |
'WebP Express was installed successfully. To start using it, you must ' .
|
67 |
+
'<a href="' . Paths::getSettingsUrl() . '">configure it here</a>.'
|
68 |
);
|
lib/admin.php
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<?php
|
2 |
|
3 |
// When an update requires a migration, the number should be increased
|
4 |
-
define('WEBPEXPRESS_MIGRATION_VERSION', '
|
5 |
|
6 |
if (WEBPEXPRESS_MIGRATION_VERSION != get_option('webp-express-migration-version', 0)) {
|
7 |
// run migration logic
|
1 |
<?php
|
2 |
|
3 |
// When an update requires a migration, the number should be increased
|
4 |
+
define('WEBPEXPRESS_MIGRATION_VERSION', '2');
|
5 |
|
6 |
if (WEBPEXPRESS_MIGRATION_VERSION != get_option('webp-express-migration-version', 0)) {
|
7 |
// run migration logic
|
lib/classes/Config.php
CHANGED
@@ -90,18 +90,62 @@ class Config
|
|
90 |
$options = $config;
|
91 |
$options['converters'] = [];
|
92 |
foreach ($config['converters'] as $converter) {
|
93 |
-
if (isset($converter['deactivated'])) continue;
|
94 |
|
95 |
$options['converters'][] = $converter;
|
96 |
}
|
97 |
foreach ($options['converters'] as &$c) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
unset ($c['id']);
|
|
|
|
|
99 |
if (!isset($c['options'])) {
|
100 |
$c = $c['converter'];
|
101 |
}
|
102 |
}
|
103 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
unset($options['image-types']);
|
|
|
|
|
|
|
105 |
return $options;
|
106 |
}
|
107 |
|
90 |
$options = $config;
|
91 |
$options['converters'] = [];
|
92 |
foreach ($config['converters'] as $converter) {
|
93 |
+
if (isset($converter['deactivated']) && ($converter['deactivated'])) continue;
|
94 |
|
95 |
$options['converters'][] = $converter;
|
96 |
}
|
97 |
foreach ($options['converters'] as &$c) {
|
98 |
+
if ($c['converter'] == 'cwebp') {
|
99 |
+
if (isset($c['options']['set-size']) && $c['options']['set-size']) {
|
100 |
+
unset($c['options']['set-size']);
|
101 |
+
} else {
|
102 |
+
unset($c['options']['set-size']);
|
103 |
+
unset($c['options']['size-in-percentage']);
|
104 |
+
}
|
105 |
+
}
|
106 |
unset ($c['id']);
|
107 |
+
unset($c['working']);
|
108 |
+
unset($c['error']);
|
109 |
if (!isset($c['options'])) {
|
110 |
$c = $c['converter'];
|
111 |
}
|
112 |
}
|
113 |
|
114 |
+
if (isset($options['cache-control'])) {
|
115 |
+
$cacheControl = $options['cache-control'];
|
116 |
+
$cacheControlOptions = [
|
117 |
+
'no-header' => '',
|
118 |
+
'one-second' => 'public, max-age=1',
|
119 |
+
'one-minute' => 'public, max-age=60',
|
120 |
+
'one-hour' => 'public, max-age=3600',
|
121 |
+
'one-day' => 'public, max-age=86400',
|
122 |
+
'one-week' => 'public, max-age=604800',
|
123 |
+
'one-month' => 'public, max-age=2592000',
|
124 |
+
'one-year' => 'public, max-age=31536000',
|
125 |
+
];
|
126 |
+
|
127 |
+
if (isset($cacheControlOptions[$cacheControl])) {
|
128 |
+
$options['cache-control-header'] = $cacheControlOptions[$cacheControl];
|
129 |
+
} else {
|
130 |
+
$options['cache-control-header'] = $options['cache-control-custom'];
|
131 |
+
}
|
132 |
+
}
|
133 |
+
|
134 |
+
$auto = (isset($options['quality-auto']) && $options['quality-auto']);
|
135 |
+
$qualitySpecific = (isset($options['quality-specific']) ? $options['quality-specific'] : 70);
|
136 |
+
if ($auto) {
|
137 |
+
$options['quality'] = 'auto';
|
138 |
+
} else {
|
139 |
+
$options['quality'] = $qualitySpecific;
|
140 |
+
unset ($options['max-quality']);
|
141 |
+
}
|
142 |
+
unset($options['quality-auto']);
|
143 |
+
unset($options['quality-specific']);
|
144 |
+
|
145 |
unset($options['image-types']);
|
146 |
+
unset($options['cache-control']);
|
147 |
+
unset($options['cache-control-custom']);
|
148 |
+
|
149 |
return $options;
|
150 |
}
|
151 |
|
lib/classes/ConvertersHelper.php
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
class ConvertersHelper
|
6 |
+
{
|
7 |
+
public static $defaultConverters = [
|
8 |
+
['converter' => 'gd', 'options' => ['skip-pngs' => true]],
|
9 |
+
['converter' => 'cwebp', 'options' => [
|
10 |
+
'use-nice' => false,
|
11 |
+
'try-common-system-paths' => true,
|
12 |
+
'try-supplied-binary-for-os' => true,
|
13 |
+
'method' => 6,
|
14 |
+
'size-in-percentage' => 45,
|
15 |
+
'low-memory' => false,
|
16 |
+
'command-line-options' => '-low_memory',
|
17 |
+
]],
|
18 |
+
['converter' => 'imagick'],
|
19 |
+
['converter' => 'gmagick'],
|
20 |
+
['converter' => 'wpc', 'options' => ['quality' => 'auto']],
|
21 |
+
['converter' => 'ewww'],
|
22 |
+
];
|
23 |
+
|
24 |
+
public static function getDefaultConverterNames()
|
25 |
+
{
|
26 |
+
return array_column(self::$defaultConverters, 'converter');
|
27 |
+
}
|
28 |
+
|
29 |
+
public static function getConverterNames($converters)
|
30 |
+
{
|
31 |
+
return array_column(self::normalize($converters), 'converter');
|
32 |
+
}
|
33 |
+
|
34 |
+
public static function normalize($converters)
|
35 |
+
{
|
36 |
+
foreach ($converters as &$converter) {
|
37 |
+
if (!isset($converter['converter'])) {
|
38 |
+
$converter = ['converter' => $converter];
|
39 |
+
}
|
40 |
+
if (!isset($converter['options'])) {
|
41 |
+
$converter['options'] = [];
|
42 |
+
}
|
43 |
+
}
|
44 |
+
return $converters;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Those converters in second, but not in first will be appended to first
|
49 |
+
*/
|
50 |
+
public static function mergeConverters($first, $second)
|
51 |
+
{
|
52 |
+
$namesInFirst = self::getConverterNames($first);
|
53 |
+
$second = self::normalize($second);
|
54 |
+
|
55 |
+
foreach ($second as $converter) {
|
56 |
+
if (!in_array($converter['converter'], $namesInFirst)) {
|
57 |
+
$first[] = $converter;
|
58 |
+
}
|
59 |
+
}
|
60 |
+
return $first;
|
61 |
+
}
|
62 |
+
|
63 |
+
}
|
lib/classes/Paths.php
CHANGED
@@ -308,4 +308,18 @@ APACHE
|
|
308 |
];
|
309 |
}
|
310 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
311 |
}
|
308 |
];
|
309 |
}
|
310 |
|
311 |
+
/* Get complete url to admin (no trailing slash) */
|
312 |
+
public static function getAdminUrl()
|
313 |
+
{
|
314 |
+
if (!function_exists('get_admin_url')) {
|
315 |
+
require_once ABSPATH . 'wp-includes/link-template.php';
|
316 |
+
}
|
317 |
+
return untrailingslashit(get_admin_url());
|
318 |
+
}
|
319 |
+
|
320 |
+
public static function getSettingsUrl()
|
321 |
+
{
|
322 |
+
return self::getAdminUrl() . '/' . 'options-general.php?page=webp_express_settings_page';
|
323 |
+
}
|
324 |
+
|
325 |
}
|
lib/classes/TestRun.php
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
include_once "Config.php";
|
6 |
+
use \WebPExpress\Config;
|
7 |
+
|
8 |
+
include_once __DIR__ . '/../classes/ConvertersHelper.php';
|
9 |
+
use \WebPExpress\ConvertersHelper;
|
10 |
+
|
11 |
+
include_once "Paths.php";
|
12 |
+
use \WebPExpress\Paths;
|
13 |
+
|
14 |
+
include_once "FileHelper.php";
|
15 |
+
use \WebPExpress\FileHelper;
|
16 |
+
|
17 |
+
include_once __DIR__ . '/../../vendor/autoload.php';
|
18 |
+
use \WebPConvert\Converters\ConverterHelper;
|
19 |
+
|
20 |
+
/**
|
21 |
+
*
|
22 |
+
*/
|
23 |
+
|
24 |
+
class TestRun
|
25 |
+
{
|
26 |
+
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Get an array of working converters OR false, if tests cannot be made
|
30 |
+
*/
|
31 |
+
public static function getConverterStatus() {
|
32 |
+
$source = Paths::getWebPExpressPluginDirAbs() . '/test/small-q61.jpg';
|
33 |
+
$destination = Paths::getUploadDirAbs() . '/webp-express-test-conversion.webp';
|
34 |
+
if (!FileHelper::canCreateFile($destination)) {
|
35 |
+
$destination = Paths::getWPContentDirAbs() . '/webp-express-test-conversion.webp';
|
36 |
+
}
|
37 |
+
if (!FileHelper::canCreateFile($destination)) {
|
38 |
+
return false;
|
39 |
+
}
|
40 |
+
$workingConverters = [];
|
41 |
+
$errors = [];
|
42 |
+
|
43 |
+
// We need wod options.
|
44 |
+
// But we cannot simply use loadWodOptions - because that would leave out the deactivated
|
45 |
+
// converters. And we need to test all converters - even the deactivated ones.
|
46 |
+
// So we load config, set "deactivated" to false, and generate Wod options from the config
|
47 |
+
$config = Config::loadConfig();
|
48 |
+
if ((!$config) || (!isset($config['converters'])) || (count($config['converters']) == 0)) {
|
49 |
+
$config = [
|
50 |
+
'converters' => ConvertersHelper::$defaultConverters
|
51 |
+
];
|
52 |
+
} else {
|
53 |
+
// set deactivated to false on all converters
|
54 |
+
foreach($config['converters'] as &$converter) {
|
55 |
+
$converter['deactivated'] = false;
|
56 |
+
}
|
57 |
+
|
58 |
+
// merge missing converters in
|
59 |
+
$config['converters'] = ConvertersHelper::mergeConverters($config['converters'], ConvertersHelper::$defaultConverters);
|
60 |
+
// echo '<pre>' . print_r($config, true) . '</pre>';
|
61 |
+
|
62 |
+
}
|
63 |
+
|
64 |
+
$options = Config::generateWodOptionsFromConfigObj($config);
|
65 |
+
$options['converters'] = ConvertersHelper::normalize($options['converters']);
|
66 |
+
|
67 |
+
//echo '<pre>' . print_r($options, true) . '</pre>';
|
68 |
+
foreach ($options['converters'] as $converter) {
|
69 |
+
$converterId = $converter['converter'];
|
70 |
+
try {
|
71 |
+
$converterOptions = array_merge($options, $converter['options']);
|
72 |
+
unset($converterOptions['converters']);
|
73 |
+
|
74 |
+
ConverterHelper::runConverter($converterId, $source, $destination, $converterOptions);
|
75 |
+
$workingConverters[] = $converterId;
|
76 |
+
} catch (\Exception $e) {
|
77 |
+
//echo $e->getMessage() . '<br>';
|
78 |
+
$errors[$converterId] = $e->getMessage();
|
79 |
+
}
|
80 |
+
}
|
81 |
+
//print_r($errors);
|
82 |
+
return [
|
83 |
+
'workingConverters' => $workingConverters,
|
84 |
+
'errors' => $errors
|
85 |
+
];
|
86 |
+
}
|
87 |
+
|
88 |
+
public static function isLocalQualityDetectionWorking() {
|
89 |
+
$q = ConverterHelper::detectQualityOfJpg(
|
90 |
+
Paths::getWebPExpressPluginDirAbs() . '/test/small-q61.jpg'
|
91 |
+
);
|
92 |
+
return ($q === 61);
|
93 |
+
}
|
94 |
+
}
|
lib/migrate/migrate.php
CHANGED
@@ -36,12 +36,9 @@ if (!(State::getState('configured', false))) {
|
|
36 |
include __DIR__ . '/migrate1.php';
|
37 |
}
|
38 |
|
39 |
-
//
|
40 |
-
// (make sure to grab the option again - it might have been changed in the migration above)
|
41 |
-
/*
|
42 |
if (intval(get_option('webp-express-migration-version', 0)) == 1) {
|
43 |
// run migration 2
|
44 |
include __DIR__ . '/migrate2.php';
|
45 |
}
|
46 |
-
*/
|
47 |
}
|
36 |
include __DIR__ . '/migrate1.php';
|
37 |
}
|
38 |
|
39 |
+
// We make sure to grab the option again - it might have been changed in the migration above
|
|
|
|
|
40 |
if (intval(get_option('webp-express-migration-version', 0)) == 1) {
|
41 |
// run migration 2
|
42 |
include __DIR__ . '/migrate2.php';
|
43 |
}
|
|
|
44 |
}
|
lib/migrate/migrate1.php
CHANGED
@@ -111,7 +111,7 @@ function webpexpress_migrate1_migrateOptions()
|
|
111 |
if ($mainResult != 'failed') {
|
112 |
Messenger::addMessage(
|
113 |
'success',
|
114 |
-
'WebP Express has successfully migrated its configuration and updated the rewrite rules'
|
115 |
);
|
116 |
} else {
|
117 |
Messenger::addMessage(
|
@@ -119,7 +119,7 @@ function webpexpress_migrate1_migrateOptions()
|
|
119 |
'WebP Express has successfully migrated its configuration.' .
|
120 |
'However, WebP Express could not update the rewrite rules<br>' .
|
121 |
'You need to change some permissions. Head to the ' .
|
122 |
-
'<a href="
|
123 |
'and try to save the settings there (it will provide more information about the problem)'
|
124 |
);
|
125 |
}
|
111 |
if ($mainResult != 'failed') {
|
112 |
Messenger::addMessage(
|
113 |
'success',
|
114 |
+
'WebP Express has successfully migrated its configuration and updated the rewrite rules to 0.5.0'
|
115 |
);
|
116 |
} else {
|
117 |
Messenger::addMessage(
|
119 |
'WebP Express has successfully migrated its configuration.' .
|
120 |
'However, WebP Express could not update the rewrite rules<br>' .
|
121 |
'You need to change some permissions. Head to the ' .
|
122 |
+
'<a href="' . Paths::getSettingsUrl() . '">settings page</a> ' .
|
123 |
'and try to save the settings there (it will provide more information about the problem)'
|
124 |
);
|
125 |
}
|
lib/migrate/migrate2.php
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WebPExpress;
|
4 |
+
|
5 |
+
include_once __DIR__ . '/../classes/Paths.php';
|
6 |
+
use \WebPExpress\Paths;
|
7 |
+
|
8 |
+
include_once __DIR__ . '/../classes/Messenger.php';
|
9 |
+
use \WebPExpress\Messenger;
|
10 |
+
|
11 |
+
include_once __DIR__ . '/../classes/TestRun.php';
|
12 |
+
use \WebPExpress\TestRun;
|
13 |
+
|
14 |
+
/* helper. Remove dir recursively. No warnings - fails silently
|
15 |
+
Set $removeTheDirItself to false if you want to empty the dir
|
16 |
+
*/
|
17 |
+
function webpexpress_migrate2_rrmdir($dir, $removeTheDirItself = true) {
|
18 |
+
if (@is_dir($dir)) {
|
19 |
+
$objects = @scandir($dir);
|
20 |
+
foreach ($objects as $object) {
|
21 |
+
if ($object != "." && $object != "..") {
|
22 |
+
$file = $dir . "/" . $object;
|
23 |
+
if (@is_dir($file)) {
|
24 |
+
webpexpress_migrate2_rrmdir($file);
|
25 |
+
} else {
|
26 |
+
@unlink($file);
|
27 |
+
}
|
28 |
+
}
|
29 |
+
}
|
30 |
+
if ($removeTheDirItself) {
|
31 |
+
@rmdir($dir);
|
32 |
+
}
|
33 |
+
}
|
34 |
+
}
|
35 |
+
|
36 |
+
$testResult = TestRun::getConverterStatus();
|
37 |
+
if ($testResult) {
|
38 |
+
$workingConverters = $testResult['workingConverters'];
|
39 |
+
if (in_array('imagick', $workingConverters)) {
|
40 |
+
webpexpress_migrate2_rrmdir(Paths::getCacheDirAbs(), false);
|
41 |
+
Messenger::addMessage(
|
42 |
+
'info',
|
43 |
+
'WebP Express has emptied the image cache. In previous versions, the imagick converter ' .
|
44 |
+
'was generating images in poor quality. This has been fixed. As your system meets the ' .
|
45 |
+
'requirements of the imagick converter, it might be that you have been using that. So ' .
|
46 |
+
'to be absolutely sure you do not have inferior conversions in the cache dir, it has been emptied.'
|
47 |
+
);
|
48 |
+
}
|
49 |
+
if (in_array('gmagick', $workingConverters)) {
|
50 |
+
Messenger::addMessage(
|
51 |
+
'info',
|
52 |
+
'Good news! WebP Express is now able to use the gmagick extension for conversion - ' .
|
53 |
+
'and your server meets the requirements!'
|
54 |
+
);
|
55 |
+
}
|
56 |
+
if (in_array('cwebp', $workingConverters)) {
|
57 |
+
Messenger::addMessage(
|
58 |
+
'info',
|
59 |
+
'WebP Express added several options for the cwebp conversion method. ' .
|
60 |
+
'<a href="' . Paths::getSettingsUrl() . '">Go to the settings page to check it out</a>.'
|
61 |
+
);
|
62 |
+
}
|
63 |
+
}
|
64 |
+
Messenger::addMessage(
|
65 |
+
'info',
|
66 |
+
'WebP Express can now be configured to cache the webp images. You might want to ' .
|
67 |
+
'<a href="' . Paths::getSettingsUrl() . '">do that</a>.'
|
68 |
+
);
|
69 |
+
|
70 |
+
|
71 |
+
update_option('webp-express-migration-version', '2');
|
lib/options/css/webp-express-options-page.css
CHANGED
@@ -19,45 +19,74 @@
|
|
19 |
padding: 0;
|
20 |
}*/
|
21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
#converters li {
|
24 |
cursor: move;
|
25 |
-
border: 1px solid
|
26 |
box-shadow: 0 1px 1px rgba(0,0,0,.04);
|
27 |
line-height: 1.4em;
|
28 |
-
background-color: #
|
29 |
-
padding: 10px;
|
30 |
-
max-width:
|
|
|
|
|
|
|
31 |
}
|
32 |
#converters li:hover {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
border-color: #999;
|
34 |
-
box-shadow: 0 1px 2px rgba(0,0,0,.1);
|
35 |
}
|
36 |
#converters li.deactivated,
|
37 |
#converters li.deactivated a.configure-converter,
|
38 |
-
#converters li.deactivated a.test-converter
|
39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
}
|
41 |
#converters li a {
|
42 |
cursor: pointer;
|
43 |
}
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
|
49 |
#converters li > * {
|
50 |
vertical-align: middle;
|
51 |
|
52 |
}
|
53 |
-
#converters li >
|
54 |
display: inline-block;
|
55 |
line-height: 1;
|
56 |
}
|
57 |
-
#converters li >
|
58 |
-
font-size: 15px;
|
59 |
padding-left: 10px;
|
60 |
-
width:
|
61 |
}
|
62 |
|
63 |
#converters li > a.btn {
|
@@ -75,8 +104,61 @@
|
|
75 |
background-color: #eee;*/
|
76 |
}
|
77 |
#converters li > a.configure-converter {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
|
|
|
|
|
80 |
}
|
81 |
|
82 |
/*
|
@@ -90,9 +172,35 @@
|
|
90 |
display: inline-block;
|
91 |
}
|
92 |
|
|
|
|
|
|
|
|
|
93 |
.converter-options .info {
|
94 |
margin-bottom: 20px;
|
95 |
}
|
96 |
.converter-options button {
|
97 |
margin-top: 15px;
|
98 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
padding: 0;
|
20 |
}*/
|
21 |
|
22 |
+
@media (min-width: 782px) {
|
23 |
+
#webpexpress_settings .form-table th {
|
24 |
+
padding-top: 5px;
|
25 |
+
padding-bottom: 5px;
|
26 |
+
width: 180px;
|
27 |
+
}
|
28 |
+
#webpexpress_settings .form-table td {
|
29 |
+
padding-top: 1px;
|
30 |
+
padding-bottom: 5px;
|
31 |
+
}
|
32 |
+
|
33 |
+
}
|
34 |
|
35 |
#converters li {
|
36 |
cursor: move;
|
37 |
+
border: 1px solid grey;
|
38 |
box-shadow: 0 1px 1px rgba(0,0,0,.04);
|
39 |
line-height: 1.4em;
|
40 |
+
background-color: #fff;
|
41 |
+
padding: 10px 10px 0;
|
42 |
+
max-width: 465px;
|
43 |
+
min-height: 30px;
|
44 |
+
position: relative;
|
45 |
+
font-size: 12px;
|
46 |
}
|
47 |
#converters li:hover {
|
48 |
+
border-color: #000;
|
49 |
+
box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
50 |
+
}
|
51 |
+
#converters li.deactivated {
|
52 |
+
border-color: #ccc;
|
53 |
+
background-color: #f0f0f0;
|
54 |
+
}
|
55 |
+
#converters li.deactivated:hover {
|
56 |
border-color: #999;
|
|
|
57 |
}
|
58 |
#converters li.deactivated,
|
59 |
#converters li.deactivated a.configure-converter,
|
60 |
+
#converters li.deactivated a.test-converter,
|
61 |
+
#converters li.deactivated a.activate-converter {
|
62 |
+
color: #888;
|
63 |
+
}
|
64 |
+
#converters li.not-operational {
|
65 |
+
border-style: dotted;
|
66 |
+
border-color: #666;
|
67 |
+
}
|
68 |
+
#converters li.not-operational:hover {
|
69 |
+
border-style: solid;
|
70 |
}
|
71 |
#converters li a {
|
72 |
cursor: pointer;
|
73 |
}
|
74 |
+
#converters li[data-id='gmagick'] a.configure-converter,
|
75 |
+
#converters li[data-id='imagick'] a.configure-converter {
|
76 |
+
visibility: hidden;
|
77 |
+
}
|
78 |
|
79 |
#converters li > * {
|
80 |
vertical-align: middle;
|
81 |
|
82 |
}
|
83 |
+
#converters li > div {
|
84 |
display: inline-block;
|
85 |
line-height: 1;
|
86 |
}
|
87 |
+
#converters li > .text {
|
|
|
88 |
padding-left: 10px;
|
89 |
+
width: 205px;
|
90 |
}
|
91 |
|
92 |
#converters li > a.btn {
|
104 |
background-color: #eee;*/
|
105 |
}
|
106 |
#converters li > a.configure-converter {
|
107 |
+
}
|
108 |
+
#converters li .status {
|
109 |
+
font-size: 10px;
|
110 |
+
position: absolute;
|
111 |
+
right: 14px;
|
112 |
+
bottom: 2px;
|
113 |
+
}
|
114 |
|
115 |
+
#converters li .status svg {
|
116 |
+
padding: 5px;
|
117 |
+
}
|
118 |
+
#converters li svg#status_ok {
|
119 |
+
color: #008000;
|
120 |
+
}
|
121 |
+
#converters li.deactivated svg#status_ok {
|
122 |
+
color: #99cc99;
|
123 |
+
}
|
124 |
+
#converters li svg#status_not_ok {
|
125 |
+
color: #b11010; /* 444444 */
|
126 |
+
}
|
127 |
+
#converters li.deactivated svg#status_not_ok {
|
128 |
+
color: #999999;
|
129 |
+
}
|
130 |
+
|
131 |
+
|
132 |
+
#converters li .popup,
|
133 |
+
.help .popup {
|
134 |
+
display: none;
|
135 |
+
position: absolute;
|
136 |
+
border: 1px solid #666;
|
137 |
+
z-index:2;
|
138 |
+
background-color: #ffffaa;
|
139 |
+
padding: 8px 10px;
|
140 |
+
/*left: 22px;
|
141 |
+
top: 20px;*/
|
142 |
+
margin-top: -5px;
|
143 |
+
font-size: 12px;
|
144 |
+
/*white-space: nowrap;*/
|
145 |
+
color: #000;
|
146 |
+
min-width: 150px;
|
147 |
+
font-weight: normal;
|
148 |
+
text-align: left;
|
149 |
+
max-width: 450px;
|
150 |
+
}
|
151 |
+
#converters li.operational .popup {
|
152 |
+
background-color: #80ff80;
|
153 |
+
}
|
154 |
+
/* #converters li .status:hover .popup */
|
155 |
+
#converters li:hover .status .popup,
|
156 |
+
.help:hover .popup {
|
157 |
+
display: block;
|
158 |
+
}
|
159 |
|
160 |
+
.help .popup {
|
161 |
+
min-width: 250px;
|
162 |
}
|
163 |
|
164 |
/*
|
172 |
display: inline-block;
|
173 |
}
|
174 |
|
175 |
+
.converter-options.wpc label {
|
176 |
+
min-width: 100px;
|
177 |
+
}
|
178 |
+
|
179 |
.converter-options .info {
|
180 |
margin-bottom: 20px;
|
181 |
}
|
182 |
.converter-options button {
|
183 |
margin-top: 15px;
|
184 |
}
|
185 |
+
.converter-options div {
|
186 |
+
margin-bottom: 15px;
|
187 |
+
}
|
188 |
+
|
189 |
+
.help {
|
190 |
+
text-align: center;
|
191 |
+
display: inline-block;
|
192 |
+
border-radius: 50%;
|
193 |
+
background-color: #00a0ee;
|
194 |
+
width: 16px;
|
195 |
+
height: 16px;
|
196 |
+
border: 0px solid #00a0ee;
|
197 |
+
color: white;
|
198 |
+
font-weight: bolder;
|
199 |
+
margin-left: 7px;
|
200 |
+
cursor: pointer;
|
201 |
+
font-size: 12px;
|
202 |
+
line-height: 16px;
|
203 |
+
vertical-align: top;
|
204 |
+
font-family: sans-serif;
|
205 |
+
position: relative;
|
206 |
+
}
|
lib/options/enqueue_scripts.php
CHANGED
@@ -10,7 +10,7 @@ wp_register_script(
|
|
10 |
'webp-express-options-page',
|
11 |
plugins_url('js/webp-express-options-page.js', __FILE__),
|
12 |
['sortable'],
|
13 |
-
'0.
|
14 |
);
|
15 |
wp_enqueue_script('webp-express-options-page');
|
16 |
|
@@ -25,7 +25,7 @@ wp_register_style(
|
|
25 |
'webp-express-options-page-css',
|
26 |
plugins_url('css/webp-express-options-page.css', __FILE__),
|
27 |
null,
|
28 |
-
'0.
|
29 |
);
|
30 |
wp_enqueue_style('webp-express-options-page-css');
|
31 |
|
10 |
'webp-express-options-page',
|
11 |
plugins_url('js/webp-express-options-page.js', __FILE__),
|
12 |
['sortable'],
|
13 |
+
'0.6.0dev9'
|
14 |
);
|
15 |
wp_enqueue_script('webp-express-options-page');
|
16 |
|
25 |
'webp-express-options-page-css',
|
26 |
plugins_url('css/webp-express-options-page.css', __FILE__),
|
27 |
null,
|
28 |
+
'0.6.0dev7'
|
29 |
);
|
30 |
wp_enqueue_style('webp-express-options-page-css');
|
31 |
|
lib/options/js/webp-express-options-page.js
CHANGED
@@ -5,59 +5,79 @@ window.convertersMap = {};
|
|
5 |
|
6 |
window.currentlyEditing = '';
|
7 |
|
8 |
-
window.defaultConverters = [
|
9 |
-
{
|
10 |
-
'converter': 'cwebp',
|
11 |
-
'options': {
|
12 |
-
'use-nice': false
|
13 |
-
},
|
14 |
-
},
|
15 |
-
{
|
16 |
-
'converter': 'wpc',
|
17 |
-
},
|
18 |
-
{
|
19 |
-
'converter': 'gd',
|
20 |
-
'options': {
|
21 |
-
'skip-pngs': true
|
22 |
-
},
|
23 |
-
},
|
24 |
-
{
|
25 |
-
'converter': 'ewww',
|
26 |
-
},
|
27 |
-
{
|
28 |
-
'converter': 'imagick',
|
29 |
-
},
|
30 |
-
]
|
31 |
-
|
32 |
function resetToDefaultConverters() {
|
33 |
window.converters = window.defaultConverters;
|
34 |
}
|
35 |
|
36 |
-
function
|
37 |
// check if all available converters are in the array.
|
38 |
// if not - add!
|
39 |
// the double loop could be avoided with map. But arrays are so small, so not worth it
|
40 |
for (var i=0; i<window.defaultConverters.length; i++) {
|
41 |
-
var checkMe = window.defaultConverters[i]
|
42 |
var found = false;
|
43 |
for (var j=0; j<window.converters.length; j++) {
|
44 |
-
|
|
|
45 |
found = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
}
|
47 |
}
|
48 |
if (!found) {
|
49 |
window.converters.push(window.defaultConverters[i]);
|
50 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
}
|
|
|
53 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
function generateConverterHTML(converter) {
|
55 |
-
html = '<li data-id="' + converter['id'] + '" class="' + (converter.deactivated ? 'deactivated' : '') + '">';
|
56 |
//html += '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="17px" height="17px" viewBox="0 0 100.000000 100.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)" fill="#444444" stroke="none"><path d="M415 920 l-80 -80 165 0 165 0 -80 80 c-44 44 -82 80 -85 80 -3 0 -41 -36 -85 -80z"/><path d="M0 695 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M0 500 l0 -40 500 0 500 0 0 40 0 40 -500 0 -500 0 0 -40z"/><path d="M0 305 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M418 78 l82 -83 82 83 83 82 -165 0 -165 0 83 -82z"/></g></svg>';
|
57 |
// html += '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 9H4v2h16V9zM4 15h16v-2H4v2z"/></svg>';
|
58 |
// html += '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 100.000000 100.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)" fill="#888888" stroke="none"><path d="M415 920 l-80 -80 165 0 165 0 -80 80 c-44 44 -82 80 -85 80 -3 0 -41 -36 -85 -80z"/><path d="M0 695 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M0 500 l0 -40 500 0 500 0 0 40 0 40 -500 0 -500 0 0 -40z"/><path d="M0 305 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M418 78 l82 -83 82 83 83 82 -165 0 -165 0 83 -82z"/></g></svg>';
|
59 |
-
html += '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18"><path d="M2 13.5h14V12H2v1.5zm0-4h14V8H2v1.5zM2 4v1.5h14V4H2z"/></svg>';
|
60 |
-
html += '<
|
|
|
|
|
61 |
html += '<a class="configure-converter btn" onclick="configureConverter(\'' + converter['id'] + '\')">configure</a>';
|
62 |
html += '<a class="test-converter btn" onclick="testConverter(\'' + converter['id'] + '\')">test</a>';
|
63 |
|
@@ -68,6 +88,26 @@ html += '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox=
|
|
68 |
html += '<a class="deactivate-converter btn" onclick=deactivateConverter(\'' + converter['id'] + '\')>deactivate</a>';
|
69 |
}
|
70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
html += '</li>';
|
72 |
return html;
|
73 |
}
|
@@ -148,11 +188,51 @@ function setConvertersHTML() {
|
|
148 |
updateInputValue();
|
149 |
}
|
150 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
151 |
document.addEventListener('DOMContentLoaded', function() {
|
152 |
//resetToDefaultConverters();
|
153 |
-
|
|
|
154 |
setConvertersHTML();
|
|
|
|
|
155 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
|
157 |
//alert(sortable.toArray());
|
158 |
});
|
@@ -175,6 +255,10 @@ function setConverterOption(converter, optionName, value) {
|
|
175 |
converter['options'][optionName] = value;
|
176 |
}
|
177 |
|
|
|
|
|
|
|
|
|
178 |
function configureConverter(id) {
|
179 |
var converter = window.convertersMap[id];
|
180 |
window.currentlyEditing = id;
|
@@ -189,12 +273,25 @@ function configureConverter(id) {
|
|
189 |
document.getElementById('wpc_secret').value = getConverterOption(converter, 'secret', '');
|
190 |
document.getElementById('wpc_url_2').value = getConverterOption(converter, 'url-2', '');
|
191 |
document.getElementById('wpc_secret_2').value = getConverterOption(converter, 'secret-2', '');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
192 |
break;
|
193 |
case 'gd':
|
194 |
document.getElementById('gd_skip_pngs').checked = getConverterOption(converter, 'skip-pngs', '');
|
195 |
break;
|
196 |
case 'cwebp':
|
197 |
document.getElementById('cwebp_use_nice').checked = getConverterOption(converter, 'use-nice', '');
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
break;
|
199 |
|
200 |
}
|
@@ -214,16 +311,37 @@ function updateConverterOptions() {
|
|
214 |
setConverterOption(converter, 'secret', document.getElementById('wpc_secret').value);
|
215 |
setConverterOption(converter, 'url-2', document.getElementById('wpc_url_2').value);
|
216 |
setConverterOption(converter, 'secret-2', document.getElementById('wpc_secret_2').value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
217 |
break;
|
218 |
case 'gd':
|
219 |
setConverterOption(converter, 'skip-pngs', document.getElementById('gd_skip_pngs').checked);
|
220 |
break;
|
221 |
case 'cwebp':
|
222 |
setConverterOption(converter, 'use-nice', document.getElementById('cwebp_use_nice').checked);
|
|
|
|
|
|
|
|
|
|
|
|
|
223 |
break;
|
224 |
}
|
225 |
updateInputValue();
|
226 |
tb_remove();
|
|
|
227 |
}
|
228 |
|
229 |
function testConverter(id) {
|
5 |
|
6 |
window.currentlyEditing = '';
|
7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
function resetToDefaultConverters() {
|
9 |
window.converters = window.defaultConverters;
|
10 |
}
|
11 |
|
12 |
+
function addMissingConvertersAndOptions() {
|
13 |
// check if all available converters are in the array.
|
14 |
// if not - add!
|
15 |
// the double loop could be avoided with map. But arrays are so small, so not worth it
|
16 |
for (var i=0; i<window.defaultConverters.length; i++) {
|
17 |
+
var checkMe = window.defaultConverters[i];
|
18 |
var found = false;
|
19 |
for (var j=0; j<window.converters.length; j++) {
|
20 |
+
var checkMe2 = window.converters[j]
|
21 |
+
if (checkMe2['converter'] == checkMe['converter']) {
|
22 |
found = true;
|
23 |
+
|
24 |
+
if (checkMe['options']) {
|
25 |
+
for (var optionName in checkMe['options']) {
|
26 |
+
if (checkMe['options'].hasOwnProperty(optionName)) {
|
27 |
+
if (!checkMe2['options']) {
|
28 |
+
checkMe2['options'] = [];
|
29 |
+
}
|
30 |
+
if (!checkMe2['options'].hasOwnProperty(optionName)) {
|
31 |
+
checkMe2['options'][optionName] = checkMe['options'][optionName];
|
32 |
+
}
|
33 |
+
}
|
34 |
+
}
|
35 |
+
}
|
36 |
}
|
37 |
}
|
38 |
if (!found) {
|
39 |
window.converters.push(window.defaultConverters[i]);
|
40 |
}
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
function addMissingOptions() {
|
45 |
+
|
46 |
+
}
|
47 |
|
48 |
+
function getConversionMethodDescription(converterId) {
|
49 |
+
var descriptions = {
|
50 |
+
'cwebp': '<i>cwebp</i> binary',
|
51 |
+
'wpc': 'wpc cloud converter',
|
52 |
+
'ewww': 'ewww cloud converter',
|
53 |
+
'gd': 'Gd extension',
|
54 |
+
'imagick': 'Imagick extension',
|
55 |
+
'gmagick': 'Gmagick extension',
|
56 |
+
};
|
57 |
+
if (descriptions[converterId]) {
|
58 |
+
return descriptions[converterId];
|
59 |
}
|
60 |
+
return converterId;
|
61 |
}
|
62 |
+
|
63 |
+
function htmlEscape(str) {
|
64 |
+
return str
|
65 |
+
.replace(/&/g, '&')
|
66 |
+
.replace(/"/g, '"')
|
67 |
+
.replace(/'/g, ''')
|
68 |
+
.replace(/</g, '<')
|
69 |
+
.replace(/>/g, '>');
|
70 |
+
}
|
71 |
+
|
72 |
function generateConverterHTML(converter) {
|
73 |
+
html = '<li data-id="' + converter['id'] + '" class="' + (converter.deactivated ? 'deactivated' : '') + ' ' + (converter.working ? 'operational' : 'not-operational') + '">';
|
74 |
//html += '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="17px" height="17px" viewBox="0 0 100.000000 100.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)" fill="#444444" stroke="none"><path d="M415 920 l-80 -80 165 0 165 0 -80 80 c-44 44 -82 80 -85 80 -3 0 -41 -36 -85 -80z"/><path d="M0 695 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M0 500 l0 -40 500 0 500 0 0 40 0 40 -500 0 -500 0 0 -40z"/><path d="M0 305 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M418 78 l82 -83 82 83 83 82 -165 0 -165 0 83 -82z"/></g></svg>';
|
75 |
// html += '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 9H4v2h16V9zM4 15h16v-2H4v2z"/></svg>';
|
76 |
// html += '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 100.000000 100.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)" fill="#888888" stroke="none"><path d="M415 920 l-80 -80 165 0 165 0 -80 80 c-44 44 -82 80 -85 80 -3 0 -41 -36 -85 -80z"/><path d="M0 695 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M0 500 l0 -40 500 0 500 0 0 40 0 40 -500 0 -500 0 0 -40z"/><path d="M0 305 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M418 78 l82 -83 82 83 83 82 -165 0 -165 0 83 -82z"/></g></svg>';
|
77 |
+
html += '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18"><path d="M2 13.5h14V12H2v1.5zm0-4h14V8H2v1.5zM2 4v1.5h14V4H2z"/></svg>';
|
78 |
+
html += '<div class="text">';
|
79 |
+
html += getConversionMethodDescription(converter['id']);
|
80 |
+
html += '</div>';
|
81 |
html += '<a class="configure-converter btn" onclick="configureConverter(\'' + converter['id'] + '\')">configure</a>';
|
82 |
html += '<a class="test-converter btn" onclick="testConverter(\'' + converter['id'] + '\')">test</a>';
|
83 |
|
88 |
html += '<a class="deactivate-converter btn" onclick=deactivateConverter(\'' + converter['id'] + '\')>deactivate</a>';
|
89 |
}
|
90 |
|
91 |
+
html += '<div class="status">';
|
92 |
+
if (converter.working) {
|
93 |
+
html += '<svg id="status_ok" width="21" height="21" version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256.000000 256.000000" preserveAspectRatio="xMidYMid meet">';
|
94 |
+
html += '<g fill="currentcolor" stroke="none" transform="translate(0.000000,256.000000) scale(0.100000,-0.100000)"><path d="M1064 2545 c-406 -72 -744 -324 -927 -690 -96 -193 -127 -333 -127 -575 0 -243 33 -387 133 -585 177 -351 518 -606 907 -676 118 -22 393 -17 511 8 110 24 252 78 356 136 327 183 569 525 628 887 19 122 19 338 0 460 -81 498 -483 914 -990 1025 -101 22 -389 28 -491 10z m814 -745 c39 -27 73 -59 77 -70 9 -27 10 -25 -372 -590 -345 -510 -357 -524 -420 -512 -19 4 -98 74 -250 225 -123 121 -225 228 -228 238 -3 10 1 31 9 47 20 40 125 132 149 132 11 0 79 -59 162 -140 79 -77 146 -140 149 -140 3 0 38 48 78 108 95 143 465 678 496 720 35 46 64 42 150 -18z"/></g></svg>';
|
95 |
+
html += '<div class="popup">' + converter['id'] + ' is operational</div>';
|
96 |
+
} else {
|
97 |
+
// + converter['id'] + ' is not operational<br>';
|
98 |
+
//html += 'not operational. ';
|
99 |
+
if (converter['error']) {
|
100 |
+
html += '<svg id="status_not_ok" width="21" height="21" title="not operational" version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500.000000 500.000000" preserveAspectRatio="xMidYMid meet">';
|
101 |
+
html += '<g fill="currentcolor" stroke="none" transform="translate(0.000000,500.000000) scale(0.100000,-0.100000)"><path d="M2315 4800 c-479 -35 -928 -217 -1303 -527 -352 -293 -615 -702 -738 -1151 -104 -380 -104 -824 0 -1204 107 -389 302 -724 591 -1013 354 -354 785 -572 1279 -646 196 -30 476 -30 672 0 494 74 925 292 1279 646 354 354 571 784 646 1279 30 197 30 475 0 672 -75 495 -292 925 -646 1279 -289 289 -624 484 -1013 591 -228 62 -528 91 -767 74z m353 -511 c458 -50 874 -272 1170 -624 417 -497 536 -1174 308 -1763 -56 -145 -176 -367 -235 -434 -4 -4 -566 552 -1250 1236 l-1243 1243 94 60 c354 229 754 327 1156 282z m864 -3200 c-67 -59 -289 -179 -434 -235 -946 -366 -2024 172 -2322 1158 -47 155 -66 276 -73 453 -13 362 84 704 290 1023 l60 94 1243 -1243 c684 -684 1240 -1246 1236 -1250z"/></g></svg>';
|
102 |
+
html += '<div class="popup">';
|
103 |
+
|
104 |
+
html += htmlEscape(converter['error']);
|
105 |
+
|
106 |
+
html += '</div>';
|
107 |
+
}
|
108 |
+
}
|
109 |
+
html += '</div>';
|
110 |
+
|
111 |
html += '</li>';
|
112 |
return html;
|
113 |
}
|
188 |
updateInputValue();
|
189 |
}
|
190 |
|
191 |
+
function updateCacheControlCustomVisibility() {
|
192 |
+
var cacheControlValue = document.getElementById('cache_control_select').value;
|
193 |
+
var customEl = document.getElementById('cache_control_custom');
|
194 |
+
if (cacheControlValue == 'custom') {
|
195 |
+
customEl.setAttribute('type', 'text');
|
196 |
+
} else {
|
197 |
+
customEl.setAttribute('type', 'hidden');
|
198 |
+
}
|
199 |
+
}
|
200 |
+
|
201 |
+
function updateQualityVisibility() {
|
202 |
+
var qualityAutoEl = document.getElementById('quality_auto_select');
|
203 |
+
if (!qualityAutoEl) {
|
204 |
+
return;
|
205 |
+
}
|
206 |
+
var qualityAutoValue = qualityAutoEl.value;
|
207 |
+
var maxQualityRowEl = document.getElementById('max_quality_row');
|
208 |
+
var qualitySpecificRowEl = document.getElementById('quality_specific_row');
|
209 |
+
|
210 |
+
//alert(qualityAutoValue);
|
211 |
+
if (qualityAutoValue == 'auto_on') {
|
212 |
+
maxQualityRowEl.style['display'] = 'table-row';
|
213 |
+
qualitySpecificRowEl.style['display'] = 'none';
|
214 |
+
} else {
|
215 |
+
maxQualityRowEl.style['display'] = 'none';
|
216 |
+
qualitySpecificRowEl.style['display'] = 'table-row';
|
217 |
+
}
|
218 |
+
|
219 |
+
}
|
220 |
+
|
221 |
document.addEventListener('DOMContentLoaded', function() {
|
222 |
//resetToDefaultConverters();
|
223 |
+
addMissingConvertersAndOptions();
|
224 |
+
addMissingOptions();
|
225 |
setConvertersHTML();
|
226 |
+
updateCacheControlCustomVisibility();
|
227 |
+
updateQualityVisibility();
|
228 |
|
229 |
+
document.getElementById('cache_control_select').addEventListener('change', function() {
|
230 |
+
updateCacheControlCustomVisibility();
|
231 |
+
});
|
232 |
+
|
233 |
+
document.getElementById('quality_auto_select').addEventListener('change', function() {
|
234 |
+
updateQualityVisibility();
|
235 |
+
});
|
236 |
|
237 |
//alert(sortable.toArray());
|
238 |
});
|
255 |
converter['options'][optionName] = value;
|
256 |
}
|
257 |
|
258 |
+
function wpcQualityChanged() {
|
259 |
+
var q = document.getElementById('wpc_quality').value;
|
260 |
+
document.getElementById('wpc_max_quality_div').style['display'] = (q == 'auto' ? 'block' : 'none');
|
261 |
+
}
|
262 |
function configureConverter(id) {
|
263 |
var converter = window.convertersMap[id];
|
264 |
window.currentlyEditing = id;
|
273 |
document.getElementById('wpc_secret').value = getConverterOption(converter, 'secret', '');
|
274 |
document.getElementById('wpc_url_2').value = getConverterOption(converter, 'url-2', '');
|
275 |
document.getElementById('wpc_secret_2').value = getConverterOption(converter, 'secret-2', '');
|
276 |
+
var q = getConverterOption(converter, 'quality', 'not_set');
|
277 |
+
if (document.getElementById('wpc_quality')) {
|
278 |
+
document.getElementById('wpc_quality').value = q;
|
279 |
+
document.getElementById('wpc_max_quality_div').style['display'] = (q == 'auto' ? 'block' : 'none');
|
280 |
+
document.getElementById('wpc_max_quality').value = getConverterOption(converter, 'max-quality', 85);
|
281 |
+
}
|
282 |
+
|
283 |
break;
|
284 |
case 'gd':
|
285 |
document.getElementById('gd_skip_pngs').checked = getConverterOption(converter, 'skip-pngs', '');
|
286 |
break;
|
287 |
case 'cwebp':
|
288 |
document.getElementById('cwebp_use_nice').checked = getConverterOption(converter, 'use-nice', '');
|
289 |
+
document.getElementById('cwebp_method').value = getConverterOption(converter, 'method', '');
|
290 |
+
document.getElementById('cwebp_try_common_system_paths').checked = getConverterOption(converter, 'try-common-system-paths', '');
|
291 |
+
document.getElementById('cwebp_try_supplied_binary').checked = getConverterOption(converter, 'try-supplied-binary-for-os', '');
|
292 |
+
document.getElementById('cwebp_set_size').checked = getConverterOption(converter, 'set-size', '');
|
293 |
+
document.getElementById('cwebp_size_in_percentage').value = getConverterOption(converter, 'size-in-percentage', '');
|
294 |
+
document.getElementById('cwebp_command_line_options').value = getConverterOption(converter, 'command-line-options', '');
|
295 |
break;
|
296 |
|
297 |
}
|
311 |
setConverterOption(converter, 'secret', document.getElementById('wpc_secret').value);
|
312 |
setConverterOption(converter, 'url-2', document.getElementById('wpc_url_2').value);
|
313 |
setConverterOption(converter, 'secret-2', document.getElementById('wpc_secret_2').value);
|
314 |
+
|
315 |
+
if (document.getElementById('wpc_quality')) {
|
316 |
+
var q = document.getElementById('wpc_quality').value;
|
317 |
+
if (q == 'auto') {
|
318 |
+
setConverterOption(converter, 'quality', 'auto');
|
319 |
+
setConverterOption(converter, 'max-quality', document.getElementById('wpc_max_quality').value);
|
320 |
+
} else {
|
321 |
+
delete converter['options']['quality'];
|
322 |
+
delete converter['options']['max-quality'];
|
323 |
+
}
|
324 |
+
} else {
|
325 |
+
delete converter['options']['quality'];
|
326 |
+
delete converter['options']['max-quality'];
|
327 |
+
}
|
328 |
break;
|
329 |
case 'gd':
|
330 |
setConverterOption(converter, 'skip-pngs', document.getElementById('gd_skip_pngs').checked);
|
331 |
break;
|
332 |
case 'cwebp':
|
333 |
setConverterOption(converter, 'use-nice', document.getElementById('cwebp_use_nice').checked);
|
334 |
+
setConverterOption(converter, 'method', document.getElementById('cwebp_method').value);
|
335 |
+
setConverterOption(converter, 'try-common-system-paths', document.getElementById('cwebp_try_common_system_paths').checked);
|
336 |
+
setConverterOption(converter, 'try-supplied-binary-for-os', document.getElementById('cwebp_try_supplied_binary').checked);
|
337 |
+
setConverterOption(converter, 'set-size', document.getElementById('cwebp_set_size').checked);
|
338 |
+
setConverterOption(converter, 'size-in-percentage', document.getElementById('cwebp_size_in_percentage').value);
|
339 |
+
setConverterOption(converter, 'command-line-options', document.getElementById('cwebp_command_line_options').value);
|
340 |
break;
|
341 |
}
|
342 |
updateInputValue();
|
343 |
tb_remove();
|
344 |
+
document.getElementById('webpexpress_settings').submit();
|
345 |
}
|
346 |
|
347 |
function testConverter(id) {
|
lib/options/options-hooks.php
CHANGED
@@ -17,7 +17,7 @@ add_action('admin_post_webpexpress_settings_submit', function() {
|
|
17 |
});
|
18 |
|
19 |
global $pagenow;
|
20 |
-
if (($pagenow == 'options-general.php') && ($_GET['page'] == 'webp_express_settings_page')) {
|
21 |
add_action('admin_enqueue_scripts', function () {
|
22 |
include __DIR__ . '/enqueue_scripts.php';
|
23 |
});
|
17 |
});
|
18 |
|
19 |
global $pagenow;
|
20 |
+
if (($pagenow == 'options-general.php') && (isset($_GET['page'])) && ($_GET['page'] == 'webp_express_settings_page')) {
|
21 |
add_action('admin_enqueue_scripts', function () {
|
22 |
include __DIR__ . '/enqueue_scripts.php';
|
23 |
});
|
lib/options/page-messages.php
CHANGED
@@ -8,6 +8,8 @@ use \WebPExpress\Messenger;
|
|
8 |
use \WebPExpress\PlatformInfo;
|
9 |
use \WebPExpress\FileHelper;
|
10 |
|
|
|
|
|
11 |
if ((!State::getState('configured', false))) {
|
12 |
include __DIR__ . "/page-welcome.php";
|
13 |
}
|
8 |
use \WebPExpress\PlatformInfo;
|
9 |
use \WebPExpress\FileHelper;
|
10 |
|
11 |
+
//include __DIR__ . "/page-welcome.php";
|
12 |
+
|
13 |
if ((!State::getState('configured', false))) {
|
14 |
include __DIR__ . "/page-welcome.php";
|
15 |
}
|
lib/options/page-welcome.php
CHANGED
@@ -5,7 +5,7 @@ use \WebPExpress\Config;
|
|
5 |
use \WebPExpress\State;
|
6 |
use \WebPExpress\Messenger;
|
7 |
use \WebPExpress\PlatformInfo;
|
8 |
-
|
9 |
|
10 |
$indexDir = Paths::getIndexDirAbs();
|
11 |
$homeDir = Paths::getHomeDirAbs();
|
@@ -13,12 +13,38 @@ $wpContentDir = Paths::getWPContentDirAbs();
|
|
13 |
$pluginDir = Paths::getPluginDirAbs();
|
14 |
$uploadDir = Paths::getUploadDirAbs();
|
15 |
|
16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
echo '<h3>Welcome!</h3>';
|
18 |
-
echo '<p>The rewrite rules are not active yet. They will be activated the first time you click the "Save settings" button.</p>';
|
19 |
-
echo '<p>Before you do that, I suggest you find out which converters that works. Start from the top. Click "test" next to a converter to test it. Try also clicking the "configure" buttons</p>';
|
20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
|
|
22 |
if (Paths::isWPContentDirMovedOutOfAbsPath()) {
|
23 |
if (!Paths::canWriteHTAccessRulesHere($wpContentDir)) {
|
24 |
echo '<p><b>Oh, one more thing</b>. Unless you are going to put the rewrite rules into your configuration manually, ';
|
@@ -104,7 +130,7 @@ if (Paths::isWPContentDirMovedOutOfAbsPath()) {
|
|
104 |
}
|
105 |
}
|
106 |
}
|
107 |
-
|
108 |
/*
|
109 |
if(Paths::canWriteHTAccessRulesHere($wpContentDir)) {
|
110 |
|
5 |
use \WebPExpress\State;
|
6 |
use \WebPExpress\Messenger;
|
7 |
use \WebPExpress\PlatformInfo;
|
8 |
+
|
9 |
|
10 |
$indexDir = Paths::getIndexDirAbs();
|
11 |
$homeDir = Paths::getHomeDirAbs();
|
13 |
$pluginDir = Paths::getPluginDirAbs();
|
14 |
$uploadDir = Paths::getUploadDirAbs();
|
15 |
|
16 |
+
$weKnowThereAreNoWorkingConverters = false;
|
17 |
+
if ($testResult !== false) {
|
18 |
+
$workingConverters = $testResult['workingConverters'];
|
19 |
+
$weKnowThereAreNoWorkingConverters = (count($workingConverters) == 0);
|
20 |
+
}
|
21 |
+
$bgColor = ($weKnowThereAreNoWorkingConverters ? '#fff' : '#cfc');
|
22 |
+
echo '<div style="background-color: ' . $bgColor . '; padding: 10px 20px; border: 1px solid #ccc; color: black; margin-top:15px">';
|
23 |
echo '<h3>Welcome!</h3>';
|
|
|
|
|
24 |
|
25 |
+
//if ($localQualityDetectionWorking) {
|
26 |
+
//echo 'Local quality detection working :)';
|
27 |
+
//}
|
28 |
+
|
29 |
+
if ($weKnowThereAreNoWorkingConverters) {
|
30 |
+
echo '<p>Unfortunately none of the local conversion methods are available on your server. ' .
|
31 |
+
'but do not despear! - You have options!' .
|
32 |
+
'<ol style="list-style-position:outside">' .
|
33 |
+
'<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>' .
|
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, gd, imagick or gmagick. 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></p>' .
|
37 |
+
"<p>Btw, don't worry, your images still works. The rewrite rules will not be saved until you click the " .
|
38 |
+
'"Save settings" button (and you also have "Response on failure" set to "Original image", so they will work even if you click save)</p>';
|
39 |
+
} else {
|
40 |
+
echo '<p>The rewrite rules are not active yet. They will be activated the first time you click the "Save settings" button.</p>';
|
41 |
+
}
|
42 |
+
//echo 'working converters:';
|
43 |
+
//print_r($workingConverters);
|
44 |
+
|
45 |
+
//echo '<p>Before you do that, I suggest you find out which converters that works. Start from the top. Click "test" next to a converter to test it. Try also clicking the "configure" buttons</p>';
|
46 |
|
47 |
+
/*
|
48 |
if (Paths::isWPContentDirMovedOutOfAbsPath()) {
|
49 |
if (!Paths::canWriteHTAccessRulesHere($wpContentDir)) {
|
50 |
echo '<p><b>Oh, one more thing</b>. Unless you are going to put the rewrite rules into your configuration manually, ';
|
130 |
}
|
131 |
}
|
132 |
}
|
133 |
+
*/
|
134 |
/*
|
135 |
if(Paths::canWriteHTAccessRulesHere($wpContentDir)) {
|
136 |
|
lib/options/page.php
CHANGED
@@ -3,6 +3,9 @@
|
|
3 |
include_once __DIR__ . '/../classes/Config.php';
|
4 |
use \WebPExpress\Config;
|
5 |
|
|
|
|
|
|
|
6 |
include_once __DIR__ . '/../classes/FileHelper.php';
|
7 |
use \WebPExpress\FileHelper;
|
8 |
|
@@ -21,6 +24,8 @@ use \WebPExpress\PlatformInfo;
|
|
21 |
include_once __DIR__ . '/../classes/State.php';
|
22 |
use \WebPExpress\State;
|
23 |
|
|
|
|
|
24 |
|
25 |
if (!current_user_can('manage_options')) {
|
26 |
wp_die('You do not have sufficient permissions to access this page.');
|
@@ -30,6 +35,25 @@ if (!current_user_can('manage_options')) {
|
|
30 |
<h2>WebP Express Settings</h2>
|
31 |
|
32 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
include __DIR__ . "/page-messages.php";
|
34 |
|
35 |
/*
|
@@ -40,38 +64,132 @@ foreach (Paths::getHTAccessDirs() as $dir) {
|
|
40 |
|
41 |
|
42 |
$defaultConfig = [
|
43 |
-
'
|
|
|
|
|
44 |
'fail' => 'original',
|
|
|
|
|
|
|
45 |
'max-quality' => 80,
|
46 |
-
'
|
47 |
-
'
|
48 |
];
|
49 |
|
|
|
|
|
|
|
50 |
$config = Config::loadConfig();
|
|
|
51 |
if (!$config) {
|
52 |
$config = [];
|
53 |
}
|
|
|
54 |
|
55 |
$config = array_merge($defaultConfig, $config);
|
56 |
if ($config['converters'] == null) {
|
57 |
$config['converters'] = [];
|
58 |
}
|
59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
// Generate a custom nonce value.
|
61 |
$webpexpress_settings_nonce = wp_create_nonce('webpexpress_settings_nonce');
|
|
|
|
|
|
|
|
|
|
|
62 |
|
63 |
-
|
|
|
64 |
?>
|
65 |
<input type="hidden" name="action" value="webpexpress_settings_submit">
|
66 |
<input type="hidden" name="webpexpress_settings_nonce" value="<?php echo $webpexpress_settings_nonce ?>" />
|
67 |
|
68 |
<?php
|
69 |
|
|
|
|
|
|
|
70 |
echo '<table class="form-table"><tbody>';
|
71 |
|
72 |
// Image types
|
73 |
// ------------
|
74 |
-
echo '<tr><th scope="row">Image types to convert
|
|
|
|
|
75 |
|
76 |
// bitmask
|
77 |
// 1: JPEGs
|
@@ -89,9 +207,115 @@ echo '</select>';
|
|
89 |
|
90 |
echo '</td></tr>';
|
91 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
// Response on failure
|
93 |
// --------------------
|
94 |
-
echo '<tr><th scope="row">Response on failure
|
|
|
|
|
95 |
|
96 |
//$fail = get_option('webp_express_failure_response');
|
97 |
$fail = $config['fail'];
|
@@ -104,18 +328,6 @@ echo '</select>';
|
|
104 |
echo '</td></tr>';
|
105 |
// echo '<tr><td colspan=2>Determines what the converter should serve, in case the image conversion should fail. For production servers, recommended value is "Original image". For development servers, choose anything you like, but that</td></tr>';
|
106 |
|
107 |
-
// Max quality
|
108 |
-
// --------------------
|
109 |
-
//$maxQuality = get_option('webp_express_max_quality');
|
110 |
-
$maxQuality = $config['max-quality'];
|
111 |
-
|
112 |
-
echo '<tr><th scope="row">Max quality (0-100)</th><td>';
|
113 |
-
echo '<input type="text" name="max-quality" value="' . $maxQuality . '">';
|
114 |
-
echo '</td></tr>';
|
115 |
-
// echo '<tr><td colspan=2><p>Converted jpeg images will get same quality as original, but not more than this setting. Something between 70-85 is recommended for most websites.</p></td></tr>';
|
116 |
-
|
117 |
-
// method
|
118 |
-
//echo '<p>When higher values are used, the encoder will spend more time inspecting additional encoding possibilities and decide on the quality gain. Supported by cwebp, wpc and imagick</p>';
|
119 |
|
120 |
echo '</tbody></table>';
|
121 |
|
@@ -124,6 +336,8 @@ echo '</tbody></table>';
|
|
124 |
|
125 |
$converters = $config['converters'];
|
126 |
echo '<script>window.converters = ' . json_encode($converters) . '</script>';
|
|
|
|
|
127 |
echo "<input type='text' name='converters' value='' style='visibility:hidden' />";
|
128 |
|
129 |
// https://premium.wpmudev.org/blog/handling-form-submissions/
|
@@ -157,10 +371,13 @@ http://php.net/manual/en/function.set-include-path.php
|
|
157 |
//echo 'All se bools: ' . print_r($output6, true) . '. Return code:' . $returnCode5;
|
158 |
*/
|
159 |
|
160 |
-
echo '<h2>
|
161 |
$dragIcon = '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="17px" height="17px" viewBox="0 0 100.000000 100.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)" fill="#444444" stroke="none"><path d="M415 920 l-80 -80 165 0 165 0 -80 80 c-44 44 -82 80 -85 80 -3 0 -41 -36 -85 -80z"/><path d="M0 695 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M0 500 l0 -40 500 0 500 0 0 40 0 40 -500 0 -500 0 0 -40z"/><path d="M0 305 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M418 78 l82 -83 82 83 83 82 -165 0 -165 0 83 -82z"/></g></svg>';
|
162 |
|
163 |
-
echo '<p><i>Drag to reorder. The
|
|
|
|
|
|
|
164 |
// https://github.com/RubaXa/Sortable
|
165 |
|
166 |
// Empty list of converters. The list will be populated by the javascript
|
@@ -168,60 +385,86 @@ echo '<ul id="converters"></ul>';
|
|
168 |
?>
|
169 |
<div id="cwebp" style="display:none;">
|
170 |
<div class="cwebp converter-options">
|
171 |
-
<h3>cwebp</h3>
|
172 |
-
<div class="info">
|
173 |
-
cwebp works by executing the cwebp binary from Google. This should normally be your first choice.
|
174 |
-
Its best in terms of quality, speed and options.
|
175 |
-
The only catch is that it requires the exec function to be enabled, and that the webserver user is
|
176 |
-
allowed to execute the cwebp binary (either at known system locations, or one of the precompiled binaries,
|
177 |
-
that comes with this library).
|
178 |
-
If you are on a shared host that doesn't allow that, the second best choice would probably be the wpc cloud converter.
|
179 |
-
</div>
|
180 |
<h3>cweb options</h3>
|
181 |
<div>
|
182 |
<label for="cwebp_use_nice">Use nice</label>
|
183 |
<input type="checkbox" id="cwebp_use_nice">
|
184 |
-
<br>Enabling
|
185 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
186 |
</div>
|
187 |
<br>
|
188 |
-
<button onclick="updateConverterOptions()" class="button button-primary" type="button">Update</button>
|
189 |
<!-- <a href="javascript: tb_remove();">close</a> -->
|
190 |
</div>
|
191 |
</div>
|
192 |
<div id="gd" style="display:none;">
|
193 |
-
<div class="
|
194 |
-
<h3>Gd</h3>
|
195 |
-
<p>
|
196 |
-
The gd converter uses the Gd extension to do the conversion. It is per default placed below the cloud converters for two reasons.
|
197 |
-
Firstly, it does not seem to produce quite as good quality as cwebp.
|
198 |
-
Secondly, it provides no conversion options, besides quality.
|
199 |
-
The Gd extension is pretty common, so the main feature of this converter is that it <i>may</i> work out of the box.
|
200 |
-
This is in contrast to the cloud converters, which requires that the user does some setup.
|
201 |
-
</p>
|
202 |
<h3>Gd options</h3>
|
203 |
-
<div class="info">
|
204 |
-
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, the converter defaults to skip PNG's.
|
205 |
-
</div>
|
206 |
<div>
|
207 |
<label for="gd_skip_pngs">Skip PNGs</label>
|
208 |
<input type="checkbox" id="gd_skip_pngs">
|
|
|
|
|
|
|
209 |
</div>
|
210 |
<br>
|
211 |
-
<button onclick="updateConverterOptions()" class="button button-primary" type="button">Update</button>
|
212 |
<!-- <a href="javascript: tb_remove();">close</a> -->
|
213 |
</div>
|
214 |
</div>
|
215 |
<div id="imagick" style="display:none;">
|
216 |
<div class="imagick converter-options">
|
217 |
-
<h3>Imagick</h3>
|
218 |
-
<p>
|
219 |
-
imagick would be your last choice. For some reason it produces conversions that are only marginally better than the originals.
|
220 |
-
See <a href="https://github.com/rosell-dk/webp-convert/issues/43" target="_blank">this issue</a>. But it is fast.
|
221 |
-
</p>
|
222 |
<h3>Imagick options</h3>
|
223 |
<div class="info">
|
224 |
-
imagick has no
|
225 |
</div>
|
226 |
<br>
|
227 |
<!--
|
@@ -234,14 +477,11 @@ echo '<ul id="converters"></ul>';
|
|
234 |
<div class="ewww converter-options">
|
235 |
<h3>Ewww</h3>
|
236 |
<p>
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
ewww however only provides one conversion option (quality), and it does not support "auto"
|
241 |
-
quality (yet - I have requested the feature and the maintainer are considering it).
|
242 |
-
Also, it is not free. But very cheap. Like in almost free.
|
243 |
</p>
|
244 |
-
<h3>
|
245 |
<div>
|
246 |
<label for="ewww_key">Key</label>
|
247 |
<input type="text" id="ewww_key" placeholder="Your API key here">
|
@@ -253,24 +493,18 @@ echo '<ul id="converters"></ul>';
|
|
253 |
<input type="text" id="ewww_key_2" placeholder="In case the first one expires...">
|
254 |
</div>
|
255 |
<br>
|
256 |
-
<button onclick="updateConverterOptions()" class="button button-primary" type="button">Update</button>
|
257 |
<!-- <a href="javascript: tb_remove();">close</a> -->
|
258 |
</div>
|
259 |
</div>
|
260 |
<div id="wpc" style="display:none;">
|
261 |
<div class="wpc converter-options">
|
262 |
-
<h3>WebPConvert Cloud Service</h3>
|
263 |
-
wpc is an open source cloud converter based on <a href="https://github.com/rosell-dk/webp-convert" target="_blank">WebPConvert</a
|
264 |
-
|
265 |
-
Conversions will of course be slower than cwebp, as images need to go back and forth to the cloud converter.
|
266 |
-
As images usually just needs to be converted once, the slower conversion
|
267 |
-
speed is probably acceptable. The conversion quality and options of wpc matches cwebp.
|
268 |
-
The only catch is that you will need to install the WPC library on a server (or have someone do it for you).
|
269 |
<a href="https://github.com/rosell-dk/webp-convert-cloud-service" target="blank">Visit WPC on github</a>.
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
<h3>Options for WebPConvert Cloud Service</h3>
|
274 |
<div>
|
275 |
<label for="wpc_url">URL</label>
|
276 |
<input type="text" id="wpc_url" placeholder="Url to your WPC instance">
|
@@ -280,7 +514,30 @@ echo '<ul id="converters"></ul>';
|
|
280 |
<label for="wpc_secret">Secret</label>
|
281 |
<input type="text" id="wpc_secret" placeholder="Secret (must match secret on server side)">
|
282 |
</div>
|
283 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
284 |
<h4>Fallback (optional)</h4>
|
285 |
<p>In case the first is down, the fallback will be used.</p>
|
286 |
<div>
|
@@ -292,13 +549,13 @@ echo '<ul id="converters"></ul>';
|
|
292 |
<input type="text" id="wpc_secret_2" placeholder="Secret (must match secret on server side)">
|
293 |
</div>
|
294 |
<br>
|
295 |
-
<button onclick="updateConverterOptions()" class="button button-primary" type="button">Update</button>
|
296 |
</div>
|
297 |
</div>
|
298 |
|
299 |
<table>
|
300 |
<tr>
|
301 |
-
<td style="padding-right:20px"><?php submit_button('Save settings'); ?></td>
|
302 |
<td><?php submit_button('Save settings and force new .htaccess rules', 'secondary', 'force'); ?></td>
|
303 |
</tr>
|
304 |
</table>
|
3 |
include_once __DIR__ . '/../classes/Config.php';
|
4 |
use \WebPExpress\Config;
|
5 |
|
6 |
+
include_once __DIR__ . '/../classes/ConvertersHelper.php';
|
7 |
+
use \WebPExpress\ConvertersHelper;
|
8 |
+
|
9 |
include_once __DIR__ . '/../classes/FileHelper.php';
|
10 |
use \WebPExpress\FileHelper;
|
11 |
|
24 |
include_once __DIR__ . '/../classes/State.php';
|
25 |
use \WebPExpress\State;
|
26 |
|
27 |
+
include_once __DIR__ . '/../classes/TestRun.php';
|
28 |
+
use \WebPExpress\TestRun;
|
29 |
|
30 |
if (!current_user_can('manage_options')) {
|
31 |
wp_die('You do not have sufficient permissions to access this page.');
|
35 |
<h2>WebP Express Settings</h2>
|
36 |
|
37 |
<?php
|
38 |
+
|
39 |
+
//update_option('webp-express-migration-version', '1');
|
40 |
+
|
41 |
+
// Test converters
|
42 |
+
$testResult = TestRun::getConverterStatus();
|
43 |
+
$workingConverters = [];
|
44 |
+
if ($testResult) {
|
45 |
+
$workingConverters = $testResult['workingConverters'];
|
46 |
+
//print_r($testResult);
|
47 |
+
} else {
|
48 |
+
Messenger::printMessage(
|
49 |
+
'error',
|
50 |
+
'WebP Express cannot save a test conversion, because it does not have write ' .
|
51 |
+
'access to your upload folder, nor your wp-content folder. Please provide!'
|
52 |
+
);
|
53 |
+
}
|
54 |
+
|
55 |
+
$canDetectQuality = TestRun::isLocalQualityDetectionWorking();
|
56 |
+
|
57 |
include __DIR__ . "/page-messages.php";
|
58 |
|
59 |
/*
|
64 |
|
65 |
|
66 |
$defaultConfig = [
|
67 |
+
'cache-control' => 'no-header',
|
68 |
+
'cache-control-custom' => 'public, max-age:3600',
|
69 |
+
'converters' => [],
|
70 |
'fail' => 'original',
|
71 |
+
'forward-query-string' => true,
|
72 |
+
'image-types' => 1,
|
73 |
+
'quality-auto' => $canDetectQuality,
|
74 |
'max-quality' => 80,
|
75 |
+
'quality-specific' => 70,
|
76 |
+
'metadata' => 'none',
|
77 |
];
|
78 |
|
79 |
+
$defaultConverters = ConvertersHelper::$defaultConverters;
|
80 |
+
|
81 |
+
|
82 |
$config = Config::loadConfig();
|
83 |
+
//echo '<pre>' . print_r($config, true) . '</pre>';
|
84 |
if (!$config) {
|
85 |
$config = [];
|
86 |
}
|
87 |
+
//$config = [];
|
88 |
|
89 |
$config = array_merge($defaultConfig, $config);
|
90 |
if ($config['converters'] == null) {
|
91 |
$config['converters'] = [];
|
92 |
}
|
93 |
|
94 |
+
if (count($config['converters']) == 0) {
|
95 |
+
// This is first time visit!
|
96 |
+
|
97 |
+
if (count($workingConverters) == 0) {
|
98 |
+
// No converters are working
|
99 |
+
// Send ewww converter to top
|
100 |
+
$resultPart1 = [];
|
101 |
+
$resultPart2 = [];
|
102 |
+
foreach ($defaultConverters as $converter) {
|
103 |
+
$converterId = $converter['converter'];
|
104 |
+
if ($converterId == 'ewww') {
|
105 |
+
$resultPart1[] = $converter;
|
106 |
+
} else {
|
107 |
+
$resultPart2[] = $converter;
|
108 |
+
}
|
109 |
+
}
|
110 |
+
$config['converters'] = array_merge($resultPart1, $resultPart2);
|
111 |
+
} else {
|
112 |
+
// Send converters not working to the bottom
|
113 |
+
// - and also deactivate them..
|
114 |
+
$resultPart1 = [];
|
115 |
+
$resultPart2 = [];
|
116 |
+
foreach ($defaultConverters as $converter) {
|
117 |
+
$converterId = $converter['converter'];
|
118 |
+
if (in_array($converterId, $workingConverters)) {
|
119 |
+
$resultPart1[] = $converter;
|
120 |
+
} else {
|
121 |
+
$converter['deactivated'] = true;
|
122 |
+
$resultPart2[] = $converter;
|
123 |
+
}
|
124 |
+
}
|
125 |
+
$config['converters'] = array_merge($resultPart1, $resultPart2);
|
126 |
+
}
|
127 |
+
|
128 |
+
// $workingConverters
|
129 |
+
//echo '<pre>' . print_r($converters, true) . '</pre>';
|
130 |
+
} else {
|
131 |
+
// not first time visit...
|
132 |
+
// merge missing converters in
|
133 |
+
$config['converters'] = ConvertersHelper::mergeConverters($config['converters'], ConvertersHelper::$defaultConverters);
|
134 |
+
}
|
135 |
+
|
136 |
+
|
137 |
+
// Set "working" and "error" properties
|
138 |
+
if ($testResult) {
|
139 |
+
foreach ($config['converters'] as &$converter) {
|
140 |
+
$converterId = $converter['converter'];
|
141 |
+
$hasError = isset($testResult['errors'][$converterId]);
|
142 |
+
$working = !$hasError;
|
143 |
+
if (isset($converter['working']) && ($converter['working'] != $working)) {
|
144 |
+
if ($working) {
|
145 |
+
Messenger::printMessage(
|
146 |
+
'info',
|
147 |
+
'Hurray! - The <i>' . $converterId . '</i> conversion method is working now!'
|
148 |
+
);
|
149 |
+
} else {
|
150 |
+
Messenger::printMessage(
|
151 |
+
'warning',
|
152 |
+
'Sad news. The <i>' . $converterId . '</i> conversion method is not working anymore. What happened?'
|
153 |
+
);
|
154 |
+
}
|
155 |
+
}
|
156 |
+
$converter['working'] = $working;
|
157 |
+
if ($hasError) {
|
158 |
+
$converter['error'] = $testResult['errors'][$converterId];
|
159 |
+
} else {
|
160 |
+
unset($converter['error']);
|
161 |
+
}
|
162 |
+
}
|
163 |
+
}
|
164 |
+
//echo '<pre>' . print_r($config['converters'], true) . '</pre>';
|
165 |
+
|
166 |
+
//echo 'Working converters:' . print_r($workingConverters, true) . '<br>';
|
167 |
// Generate a custom nonce value.
|
168 |
$webpexpress_settings_nonce = wp_create_nonce('webpexpress_settings_nonce');
|
169 |
+
?>
|
170 |
+
<p>
|
171 |
+
<i>WebP Express takes care of serving autogenerated WebP images instead of jpeg/png to browsers that supports WebP.<br>
|
172 |
+
The settings below does not affect your original images - only the converted webp images, and the redirection rules.</i>
|
173 |
+
</p>
|
174 |
|
175 |
+
<?php
|
176 |
+
echo '<form id="webpexpress_settings" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" method="post" >';
|
177 |
?>
|
178 |
<input type="hidden" name="action" value="webpexpress_settings_submit">
|
179 |
<input type="hidden" name="webpexpress_settings_nonce" value="<?php echo $webpexpress_settings_nonce ?>" />
|
180 |
|
181 |
<?php
|
182 |
|
183 |
+
function helpIcon($text) {
|
184 |
+
return '<div class="help">?<div class="popup">' . $text . '</div></div>';
|
185 |
+
}
|
186 |
echo '<table class="form-table"><tbody>';
|
187 |
|
188 |
// Image types
|
189 |
// ------------
|
190 |
+
echo '<tr><th scope="row">Image types to convert';
|
191 |
+
echo helpIcon('Beware that the Gd conversion method cannot handle transparency for PNGs. PNG conversions havent been tested much yet. Please report any problems with PNG images <a target="_blank" href="https://github.com/rosell-dk/webp-convert/issues/42">here</a>');
|
192 |
+
echo '</th><td>';
|
193 |
|
194 |
// bitmask
|
195 |
// 1: JPEGs
|
207 |
|
208 |
echo '</td></tr>';
|
209 |
|
210 |
+
// Quality
|
211 |
+
// --------------------
|
212 |
+
|
213 |
+
if ($canDetectQuality) {
|
214 |
+
echo '<tr><th scope="row">Quality';
|
215 |
+
echo helpIcon('If "Auto" is selected, the converted image will get same quality as source. Auto is recommended!');
|
216 |
+
echo '</th><td>';
|
217 |
+
$qualityAuto = $config['quality-auto'];;
|
218 |
+
echo '<select id="quality_auto_select" name="quality-auto">';
|
219 |
+
echo '<option value="auto_on"' . ($qualityAuto ? ' selected' : '') . '>Auto</option>';
|
220 |
+
echo '<option value="auto_off"' . (!$qualityAuto ? ' selected' : '') . '>Specific value</option>';
|
221 |
+
echo '</select>';
|
222 |
+
|
223 |
+
echo '</td></tr>';
|
224 |
+
|
225 |
+
|
226 |
+
// Max quality
|
227 |
+
// --------------------
|
228 |
+
$maxQuality = $config['max-quality'];
|
229 |
+
|
230 |
+
echo '<tr id="max_quality_row"><th scope="row">Max quality (0-100)';
|
231 |
+
echo helpIcon('Quality is expensive byte-wise. For most websites, more than 80 is a waste of bytes. ' .
|
232 |
+
'This option allows you to limit the quality to whatever is lowest: ' .
|
233 |
+
'the quality of the source or max quality. Recommended value: Somewhere between 50-85');
|
234 |
+
echo '</th><td>';
|
235 |
+
|
236 |
+
echo '<input type="text" size=3 name="max-quality" value="' . $maxQuality . '">';
|
237 |
+
echo '</td></tr>';
|
238 |
+
} else {
|
239 |
+
|
240 |
+
}
|
241 |
+
|
242 |
+
// Quality - specific
|
243 |
+
// --------------------
|
244 |
+
$qualitySpecific = $config['quality-specific'];
|
245 |
+
|
246 |
+
echo '<tr id="quality_specific_row"><th scope="row">Quality (0-100)';
|
247 |
+
if ($canDetectQuality) {
|
248 |
+
echo helpIcon('All converted images will be encoded with this quality');
|
249 |
+
} else {
|
250 |
+
echo helpIcon('All converted images will be encoded with this quality. ' .
|
251 |
+
'For the wpc converter, you will however have the option to use override this, and use ' .
|
252 |
+
'"auto". If you install imagick or gmagick, quality can have "auto" for all convertion methods. '
|
253 |
+
);
|
254 |
+
}
|
255 |
+
echo '</th><td>';
|
256 |
+
|
257 |
+
echo '<input type="text" size=3 name="quality-specific" value="' . $qualitySpecific . '">';
|
258 |
+
echo '</td></tr>';
|
259 |
+
|
260 |
+
|
261 |
+
|
262 |
+
|
263 |
+
// echo '<tr><td colspan=2><p>Converted jpeg images will get same quality as original, but not more than this setting. Something between 70-85 is recommended for most websites.</p></td></tr>';
|
264 |
+
|
265 |
+
// method
|
266 |
+
//echo '<p>When higher values are used, the encoder will spend more time inspecting additional encoding possibilities and decide on the quality gain. Supported by cwebp, wpc and imagick</p>';
|
267 |
+
|
268 |
+
// Cache-Control
|
269 |
+
// --------------------
|
270 |
+
//$maxQuality = get_option('webp_express_max_quality');
|
271 |
+
$cacheControl = $config['cache-control'];
|
272 |
+
$cacheControlCustom = $config['cache-control-custom'];
|
273 |
+
|
274 |
+
echo '<tr><th scope="row">Caching';
|
275 |
+
echo helpIcon(
|
276 |
+
'Controls the cache-control header for the converted image. ' .
|
277 |
+
'This header is only sent when a converted image is successfully delivered (either existing, or new ' .
|
278 |
+
'conversion). In case of failure, headers will be sent to prevent caching.');
|
279 |
+
echo '</th><td>';
|
280 |
+
echo '<select id="cache_control_select" name="cache-control">';
|
281 |
+
echo '<option value="no-header"' . ($cacheControl == 'no-header' ? ' selected' : '') . '>Do not set Cache-Control header</option>';
|
282 |
+
echo '<option value="one-second"' . ($cacheControl == 'one-second' ? ' selected' : '') . '>One second</option>';
|
283 |
+
echo '<option value="one-minute"' . ($cacheControl == 'one-minute' ? ' selected' : '') . '>One minute</option>';
|
284 |
+
echo '<option value="one-hour"' . ($cacheControl == 'one-hour' ? ' selected' : '') . '>One hour</option>';
|
285 |
+
echo '<option value="one-day"' . ($cacheControl == 'one-day' ? ' selected' : '') . '>One day</option>';
|
286 |
+
echo '<option value="one-week"' . ($cacheControl == 'one-week' ? ' selected' : '') . '>One week</option>';
|
287 |
+
echo '<option value="one-month"' . ($cacheControl == 'one-month' ? ' selected' : '') . '>One month</option>';
|
288 |
+
echo '<option value="one-year"' . ($cacheControl == 'one-year' ? ' selected' : '') . '>One year</option>';
|
289 |
+
echo '<option value="custom"' . ($cacheControl == 'custom' ? ' selected' : '') . '>Custom Cache-Control header</option>';
|
290 |
+
echo '</select><br>';
|
291 |
+
echo '<input type="text" id="cache_control_custom" name="cache-control-custom" value="' . $cacheControlCustom . '">';
|
292 |
+
echo '</td></tr>';
|
293 |
+
|
294 |
+
|
295 |
+
// Metadata
|
296 |
+
// --------------------
|
297 |
+
//$maxQuality = get_option('webp_express_max_quality');
|
298 |
+
$metadata = $config['metadata'];
|
299 |
+
|
300 |
+
echo '<tr><th scope="row">Metadata';
|
301 |
+
echo helpIcon('Decide what to do with image metadata, such as Exif. Note that this setting is not supported by the "Gd" conversion method, as it is not possible to copy the metadata with the Gd extension');
|
302 |
+
echo '</th><td>';
|
303 |
+
|
304 |
+
echo '<select name="metadata">';
|
305 |
+
echo '<option value="none"' . ($metadata == 'none' ? ' selected' : '') . '>No metadata in webp</option>';
|
306 |
+
echo '<option value="all"' . ($metadata == 'all' ? ' selected' : '') . '>Copy all metadata to webp</option>';
|
307 |
+
echo '</select>';
|
308 |
+
echo '</td></tr>';
|
309 |
+
// echo '<tr><td colspan=2><p>Converted jpeg images will get same quality as original, but not more than this setting. Something between 70-85 is recommended for most websites.</p></td></tr>';
|
310 |
+
|
311 |
+
// method
|
312 |
+
//echo '<p>When higher values are used, the encoder will spend more time inspecting additional encoding possibilities and decide on the quality gain. Supported by cwebp, wpc and imagick</p>';
|
313 |
+
|
314 |
// Response on failure
|
315 |
// --------------------
|
316 |
+
echo '<tr><th scope="row">Response on failure';
|
317 |
+
echo helpIcon('Determines what to serve in case the image conversion should fail.');
|
318 |
+
echo '</th><td>';
|
319 |
|
320 |
//$fail = get_option('webp_express_failure_response');
|
321 |
$fail = $config['fail'];
|
328 |
echo '</td></tr>';
|
329 |
// echo '<tr><td colspan=2>Determines what the converter should serve, in case the image conversion should fail. For production servers, recommended value is "Original image". For development servers, choose anything you like, but that</td></tr>';
|
330 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
331 |
|
332 |
echo '</tbody></table>';
|
333 |
|
336 |
|
337 |
$converters = $config['converters'];
|
338 |
echo '<script>window.converters = ' . json_encode($converters) . '</script>';
|
339 |
+
echo '<script>window.defaultConverters = ' . json_encode($defaultConverters) . '</script>';
|
340 |
+
|
341 |
echo "<input type='text' name='converters' value='' style='visibility:hidden' />";
|
342 |
|
343 |
// https://premium.wpmudev.org/blog/handling-form-submissions/
|
371 |
//echo 'All se bools: ' . print_r($output6, true) . '. Return code:' . $returnCode5;
|
372 |
*/
|
373 |
|
374 |
+
echo '<h2>Conversion methods to try</h2>';
|
375 |
$dragIcon = '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="17px" height="17px" viewBox="0 0 100.000000 100.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)" fill="#444444" stroke="none"><path d="M415 920 l-80 -80 165 0 165 0 -80 80 c-44 44 -82 80 -85 80 -3 0 -41 -36 -85 -80z"/><path d="M0 695 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M0 500 l0 -40 500 0 500 0 0 40 0 40 -500 0 -500 0 0 -40z"/><path d="M0 305 l0 -45 500 0 500 0 0 45 0 45 -500 0 -500 0 0 -45z"/><path d="M418 78 l82 -83 82 83 83 82 -165 0 -165 0 83 -82z"/></g></svg>';
|
376 |
|
377 |
+
echo '<p><i>Drag to reorder. The conversion method on top will first be tried. ';
|
378 |
+
echo 'Should it fail, the next will be used, etc.<br>';
|
379 |
+
echo 'To learn more about the conversion methods, ';
|
380 |
+
echo '<a target="_blank" href="https://github.com/rosell-dk/webp-convert/blob/master/docs/converters.md">Go here</a></i></p>';
|
381 |
// https://github.com/RubaXa/Sortable
|
382 |
|
383 |
// Empty list of converters. The list will be populated by the javascript
|
385 |
?>
|
386 |
<div id="cwebp" style="display:none;">
|
387 |
<div class="cwebp converter-options">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
388 |
<h3>cweb options</h3>
|
389 |
<div>
|
390 |
<label for="cwebp_use_nice">Use nice</label>
|
391 |
<input type="checkbox" id="cwebp_use_nice">
|
392 |
+
<br>Enabling this option saves system resources at the cost of slightly slower conversion
|
393 |
+
</div>
|
394 |
+
<div>
|
395 |
+
<label for="cwebp_try_common_system_paths">Try to execute cweb binary at common locations</label>
|
396 |
+
<input type="checkbox" id="cwebp_try_common_system_paths">
|
397 |
+
<br>If checked, we will look for binaries in common locations, such as <i>/usr/bin/cwebp</i>
|
398 |
+
</div>
|
399 |
+
<div>
|
400 |
+
<label for="cwebp_try_common_system_paths">Try precompiled cwebp</label>
|
401 |
+
<input type="checkbox" id="cwebp_try_supplied_binary">
|
402 |
+
<br>This plugin ships with precompiled cweb binaries for different platforms. If checked, and we have a precompiled binary for your OS, we will try to exectute it
|
403 |
+
</div>
|
404 |
+
<div>
|
405 |
+
<label for="cwebp_method">Method (0-6)</label>
|
406 |
+
<input type="text" size="2" id="cwebp_method">
|
407 |
+
<br>This parameter controls the trade off between encoding speed and the compressed file size and quality.
|
408 |
+
Possible values range from 0 to 6. 0 is fastest. 6 results in best quality.
|
409 |
+
</div>
|
410 |
+
<div>
|
411 |
+
<label for="cwebp_set_size">Set size option (and ignore quality option)</label>
|
412 |
+
<input type="checkbox" id="cwebp_set_size">
|
413 |
+
<br>This option activates the size option below.
|
414 |
+
<?php
|
415 |
+
if ($canDetectQuality) {
|
416 |
+
echo 'As you have quality detection working on your server, it is probably best to use that, rather ';
|
417 |
+
echo 'than the "size" option. Using the size option takes more ressources (it takes about 2.5 times ';
|
418 |
+
echo 'longer for cwebp to do a a conversion with the size option than the quality option). Long ';
|
419 |
+
echo 'story short, you should probably <i>not</i> activate the size option.';
|
420 |
+
} else {
|
421 |
+
echo 'As you do not have quality detection working on your server, it is probably a good ';
|
422 |
+
echo 'idea to use the size option to avoid making conversions with a higher quality setting ';
|
423 |
+
echo 'than the source image. ';
|
424 |
+
echo 'Beware, though, that cwebp takes about 2.5 times longer to do a a conversion with the size option set.';
|
425 |
+
}
|
426 |
+
?>
|
427 |
+
</div>
|
428 |
+
<div>
|
429 |
+
<label for="cwebp_size_in_percentage">Size (in percentage of source)</label>
|
430 |
+
<input type="text" size="2" id="cwebp_size_in_percentage">
|
431 |
+
<br>Set the cwebp should aim for, in percentage of the original.
|
432 |
+
Usually cwebp can reduce to ~45% of original without loosing quality.
|
433 |
+
</div>
|
434 |
+
<div>
|
435 |
+
<label for="cwebp_command_line_options">Extra command line options</label><br>
|
436 |
+
<input type="text" size="40" id="cwebp_command_line_options" style="width:100%">
|
437 |
+
<br>This allows you to set any parameter available for cwebp in the same way as
|
438 |
+
you would do when executing <i>cwebp</i>. As a syntax example, you could ie. set it to
|
439 |
+
"-low_memory -af -f 50 -sharpness 0 -mt -crop 10 10 40 40" (do not include the quotes).
|
440 |
+
Read more about all the available parameters in
|
441 |
+
<a target="_blank" href="https://developers.google.com/speed/webp/docs/cwebp">the docs</a>
|
442 |
</div>
|
443 |
<br>
|
444 |
+
<button onclick="updateConverterOptions()" class="button button-primary" type="button">Update and save settings</button>
|
445 |
<!-- <a href="javascript: tb_remove();">close</a> -->
|
446 |
</div>
|
447 |
</div>
|
448 |
<div id="gd" style="display:none;">
|
449 |
+
<div class="gd converter-options">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
450 |
<h3>Gd options</h3>
|
|
|
|
|
|
|
451 |
<div>
|
452 |
<label for="gd_skip_pngs">Skip PNGs</label>
|
453 |
<input type="checkbox" id="gd_skip_pngs">
|
454 |
+
<br>Gd is not suited for converting PNGs into webp. –
|
455 |
+
The filesize is generally much larger than the original.
|
456 |
+
For this reason, the converter defaults to skip PNG's.
|
457 |
</div>
|
458 |
<br>
|
459 |
+
<button onclick="updateConverterOptions()" class="button button-primary" type="button">Update and save settings</button>
|
460 |
<!-- <a href="javascript: tb_remove();">close</a> -->
|
461 |
</div>
|
462 |
</div>
|
463 |
<div id="imagick" style="display:none;">
|
464 |
<div class="imagick converter-options">
|
|
|
|
|
|
|
|
|
|
|
465 |
<h3>Imagick options</h3>
|
466 |
<div class="info">
|
467 |
+
imagick has no special options.
|
468 |
</div>
|
469 |
<br>
|
470 |
<!--
|
477 |
<div class="ewww converter-options">
|
478 |
<h3>Ewww</h3>
|
479 |
<p>
|
480 |
+
ewww is a cloud service for converting images.
|
481 |
+
To use it, you need to purchase a key <a target="_blank" href="https://ewww.io/plans/">here</a>.
|
482 |
+
They do not charge credits for webp conversions, so all you ever have to pay is the one dollar start-up fee :)
|
|
|
|
|
|
|
483 |
</p>
|
484 |
+
<h3>Options</h3>
|
485 |
<div>
|
486 |
<label for="ewww_key">Key</label>
|
487 |
<input type="text" id="ewww_key" placeholder="Your API key here">
|
493 |
<input type="text" id="ewww_key_2" placeholder="In case the first one expires...">
|
494 |
</div>
|
495 |
<br>
|
496 |
+
<button onclick="updateConverterOptions()" class="button button-primary" type="button">Update and save settings</button>
|
497 |
<!-- <a href="javascript: tb_remove();">close</a> -->
|
498 |
</div>
|
499 |
</div>
|
500 |
<div id="wpc" style="display:none;">
|
501 |
<div class="wpc converter-options">
|
502 |
+
<h3>WebPConvert Cloud Service (WPC)</h3>
|
503 |
+
wpc is an open source cloud converter based on <a href="https://github.com/rosell-dk/webp-convert" target="_blank">WebPConvert</a>.
|
504 |
+
You will need to install the WPC library on a server (or have someone do it for you).
|
|
|
|
|
|
|
|
|
505 |
<a href="https://github.com/rosell-dk/webp-convert-cloud-service" target="blank">Visit WPC on github</a>.
|
506 |
+
(PS: It is planned to integrate wpc into <i>WebP Express</i>, making it very easy to share the capability to convert with your other sites)
|
507 |
+
<h3>Options</h3>
|
|
|
|
|
508 |
<div>
|
509 |
<label for="wpc_url">URL</label>
|
510 |
<input type="text" id="wpc_url" placeholder="Url to your WPC instance">
|
514 |
<label for="wpc_secret">Secret</label>
|
515 |
<input type="text" id="wpc_secret" placeholder="Secret (must match secret on server side)">
|
516 |
</div>
|
517 |
+
<?php
|
518 |
+
if ($canDetectQuality) { ?>
|
519 |
+
<div>
|
520 |
+
<label for="wpc_quality">
|
521 |
+
Quality
|
522 |
+
<?php echo helpIcon('If "Auto" is selected, the converted image will get same quality as source. Auto is recommended!'); ?>
|
523 |
+
</label>
|
524 |
+
<!--
|
525 |
+
Your server cannot detect quality of jpeg files. But you can have the cloud server do it for you
|
526 |
+
(provided that <i>it</i> can) -->
|
527 |
+
<select id="wpc_quality" onchange="wpcQualityChanged()">
|
528 |
+
<option value="not_set">Use global settings</option>
|
529 |
+
<option value="auto">Auto</option>
|
530 |
+
</select>
|
531 |
+
</div>
|
532 |
+
<div id="wpc_max_quality_div">
|
533 |
+
<label>
|
534 |
+
Max quality
|
535 |
+
<?php echo helpIcon('Enter number (0-100). Converted images will be encoded with same quality as the source image, but not more than this setting'); ?>
|
536 |
+
</label>
|
537 |
+
<input type="text" size=3 id="wpc_max_quality">
|
538 |
+
</div>
|
539 |
+
<?php } ?>
|
540 |
+
<br>
|
541 |
<h4>Fallback (optional)</h4>
|
542 |
<p>In case the first is down, the fallback will be used.</p>
|
543 |
<div>
|
549 |
<input type="text" id="wpc_secret_2" placeholder="Secret (must match secret on server side)">
|
550 |
</div>
|
551 |
<br>
|
552 |
+
<button onclick="updateConverterOptions()" class="button button-primary" type="button">Update and save settings</button>
|
553 |
</div>
|
554 |
</div>
|
555 |
|
556 |
<table>
|
557 |
<tr>
|
558 |
+
<td style="padding-right:20px"><?php submit_button('Save settings', 'primary', 'mysubmit'); ?></td>
|
559 |
<td><?php submit_button('Save settings and force new .htaccess rules', 'secondary', 'force'); ?></td>
|
560 |
</tr>
|
561 |
</table>
|
lib/options/submit.php
CHANGED
@@ -17,14 +17,34 @@ use \WebPExpress\Paths;
|
|
17 |
// https://premium.wpmudev.org/blog/handling-form-submissions/
|
18 |
// checkout https://codex.wordpress.org/Function_Reference/sanitize_meta
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
$config = [
|
|
|
|
|
|
|
21 |
'fail' => sanitize_text_field($_POST['fail']),
|
22 |
-
'
|
23 |
'image-types' => sanitize_text_field($_POST['image-types']),
|
24 |
-
'
|
25 |
-
'forward-query-string' => true
|
26 |
];
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
// remove id's
|
29 |
foreach ($config['converters'] as &$converter) {
|
30 |
unset ($converter['id']);
|
@@ -40,6 +60,11 @@ Messenger::addMessage(
|
|
40 |
);*/
|
41 |
|
42 |
/*
|
|
|
|
|
|
|
|
|
|
|
43 |
Messenger::addMessage(
|
44 |
'info',
|
45 |
'<pre>' . htmlentities(print_r($result, true)) . '</pre>'
|
17 |
// https://premium.wpmudev.org/blog/handling-form-submissions/
|
18 |
// checkout https://codex.wordpress.org/Function_Reference/sanitize_meta
|
19 |
|
20 |
+
/* We want an integer value between 0-100. We round "77.5" to 78. */
|
21 |
+
function webp_express_sanitize_quality_field($text) {
|
22 |
+
$text = str_replace(',', '.', $text);
|
23 |
+
$q = floatval(sanitize_text_field($text));
|
24 |
+
$q = round($q);
|
25 |
+
return max(0, min($q, 100));
|
26 |
+
}
|
27 |
$config = [
|
28 |
+
'cache-control' => sanitize_text_field($_POST['cache-control']),
|
29 |
+
'cache-control-custom' => sanitize_text_field($_POST['cache-control-custom']),
|
30 |
+
'converters' => json_decode(wp_unslash($_POST['converters']), true), // holy moly! - https://stackoverflow.com/questions/2496455/why-are-post-variables-getting-escaped-in-php
|
31 |
'fail' => sanitize_text_field($_POST['fail']),
|
32 |
+
'forward-query-string' => true,
|
33 |
'image-types' => sanitize_text_field($_POST['image-types']),
|
34 |
+
'metadata' => sanitize_text_field($_POST['metadata']),
|
|
|
35 |
];
|
36 |
|
37 |
+
$auto = (isset($_POST['quality-auto']) && $_POST['quality-auto'] == 'auto_on');
|
38 |
+
$config['quality-auto'] = $auto;
|
39 |
+
|
40 |
+
if ($auto) {
|
41 |
+
$config['max-quality'] = webp_express_sanitize_quality_field($_POST['max-quality']);
|
42 |
+
$config['quality-specific'] = 70;
|
43 |
+
} else {
|
44 |
+
$config['max-quality'] = 80;
|
45 |
+
$config['quality-specific'] = webp_express_sanitize_quality_field($_POST['quality-specific']);
|
46 |
+
}
|
47 |
+
|
48 |
// remove id's
|
49 |
foreach ($config['converters'] as &$converter) {
|
50 |
unset ($converter['id']);
|
60 |
);*/
|
61 |
|
62 |
/*
|
63 |
+
Messenger::addMessage(
|
64 |
+
'info',
|
65 |
+
'<pre>' . htmlentities(print_r($config, true)) . '</pre>'
|
66 |
+
);
|
67 |
+
|
68 |
Messenger::addMessage(
|
69 |
'info',
|
70 |
'<pre>' . htmlentities(print_r($result, true)) . '</pre>'
|
lib/reactivate.php
CHANGED
@@ -12,6 +12,9 @@ use \WebPExpress\Messenger;
|
|
12 |
include_once __DIR__ . '/classes/Actions.php';
|
13 |
use \WebPExpress\Actions;
|
14 |
|
|
|
|
|
|
|
15 |
include_once __DIR__ . '/classes/PlatformInfo.php';
|
16 |
use \WebPExpress\PlatformInfo;
|
17 |
|
@@ -30,7 +33,8 @@ $config = Config::loadConfig();
|
|
30 |
if ($config === false) {
|
31 |
Messenger::addMessage(
|
32 |
'error',
|
33 |
-
'The config file seems to have gone missing. You will need to reconfigure WebP Express
|
|
|
34 |
);
|
35 |
} else {
|
36 |
$rulesResult = HTAccess::saveRules($config);
|
@@ -52,14 +56,15 @@ if ($config === false) {
|
|
52 |
'WebP Express re-activated successfully.<br>' .
|
53 |
'The image redirections are in effect again.<br><br>' .
|
54 |
'Just a quick reminder: If you at some point change the upload directory or move Wordpress, the <i>.htaccess</i> will need to be regenerated.<br>' .
|
55 |
-
'You do that by re-saving the settings
|
|
|
56 |
);
|
57 |
} else {
|
58 |
Messenger::addMessage(
|
59 |
'warning',
|
60 |
'WebP Express could not regenerate the rewrite rules<br>' .
|
61 |
'You need to change some permissions. Head to the ' .
|
62 |
-
'<a href="
|
63 |
'and try to save the settings there (it will provide more information about the problem)'
|
64 |
);
|
65 |
|
12 |
include_once __DIR__ . '/classes/Actions.php';
|
13 |
use \WebPExpress\Actions;
|
14 |
|
15 |
+
include_once __DIR__ . '/classes/Paths.php';
|
16 |
+
use \WebPExpress\Paths;
|
17 |
+
|
18 |
include_once __DIR__ . '/classes/PlatformInfo.php';
|
19 |
use \WebPExpress\PlatformInfo;
|
20 |
|
33 |
if ($config === false) {
|
34 |
Messenger::addMessage(
|
35 |
'error',
|
36 |
+
'The config file seems to have gone missing. You will need to reconfigure WebP Express ' .
|
37 |
+
'<a href="' . Paths::getSettingsUrl() . '">(here)</a>.'
|
38 |
);
|
39 |
} else {
|
40 |
$rulesResult = HTAccess::saveRules($config);
|
56 |
'WebP Express re-activated successfully.<br>' .
|
57 |
'The image redirections are in effect again.<br><br>' .
|
58 |
'Just a quick reminder: If you at some point change the upload directory or move Wordpress, the <i>.htaccess</i> will need to be regenerated.<br>' .
|
59 |
+
'You do that by re-saving the settings ' .
|
60 |
+
'<a href="' . Paths::getSettingsUrl() . '">(here)</a>'
|
61 |
);
|
62 |
} else {
|
63 |
Messenger::addMessage(
|
64 |
'warning',
|
65 |
'WebP Express could not regenerate the rewrite rules<br>' .
|
66 |
'You need to change some permissions. Head to the ' .
|
67 |
+
'<a href="' . Paths::getSettingsUrl() . '">settings page</a> ' .
|
68 |
'and try to save the settings there (it will provide more information about the problem)'
|
69 |
);
|
70 |
|
test/small-q61.jpg
ADDED
Binary file
|
test/test-run.php
CHANGED
@@ -10,9 +10,8 @@ if (isset($_GET['stream-webp-image'])) {
|
|
10 |
error_reporting(E_ALL);
|
11 |
ini_set("display_errors", 1);
|
12 |
|
13 |
-
|
14 |
-
|
15 |
-
require "../wod/webp-convert-and-serve.inc";
|
16 |
|
17 |
use WebPConvert\WebPConvert;
|
18 |
use WebPConvert\Loggers\EchoLogger;
|
@@ -72,12 +71,18 @@ function getConverterOptionsFromQueryString($converter)
|
|
72 |
// Set options
|
73 |
$options = [];
|
74 |
foreach ($availOptions as $optionName => $optionType) {
|
|
|
75 |
switch ($optionType) {
|
76 |
case 'string':
|
77 |
if (isset($_GET[$optionName])) {
|
78 |
$options[$optionName] = $_GET[$optionName];
|
79 |
}
|
80 |
break;
|
|
|
|
|
|
|
|
|
|
|
81 |
case 'boolean':
|
82 |
if (isset($_GET[$optionName])) {
|
83 |
$options[$optionName] = ($_GET[$optionName] == 'true');
|
@@ -92,10 +97,10 @@ $options['converters'] = [[
|
|
92 |
'options' => getConverterOptionsFromQueryString($converter)
|
93 |
]];
|
94 |
|
|
|
95 |
//echo '<pre>' . print_r($options, true) . '</pre>';
|
96 |
|
97 |
function testRun($converter, $source, $destination, $options) {
|
98 |
-
$beginTime = microtime(true);
|
99 |
|
100 |
try {
|
101 |
$success = WebPConvert::convert($source, $destination, $options, new EchoLogger());
|
@@ -103,11 +108,8 @@ function testRun($converter, $source, $destination, $options) {
|
|
103 |
$msg = $e->getMessage();
|
104 |
}
|
105 |
|
106 |
-
$endTime = microtime(true);
|
107 |
-
$duration = $endTime - $beginTime;
|
108 |
-
|
109 |
if (!$success) {
|
110 |
-
echo '<h3 class="error">Test conversion failed
|
111 |
|
112 |
if (isset($msg)) {
|
113 |
echo '<label>Problem:</label>';
|
@@ -116,21 +118,13 @@ function testRun($converter, $source, $destination, $options) {
|
|
116 |
echo '<p class="error-msg">' . $msg . '</p>';
|
117 |
}
|
118 |
} else {
|
119 |
-
echo '<p>Successfully converted test image
|
120 |
|
121 |
if (isset($_SERVER['HTTP_ACCEPT']) && (strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') !== false )) {
|
122 |
//echo '<img src="' . $_GET['destinationUrl'] . '" width=48%><br><br>';
|
123 |
echo '<img src="?stream-webp-image=' . $destination . '" width=48%><br><br>';
|
124 |
|
125 |
}
|
126 |
-
if (filesize($source) < 10000) {
|
127 |
-
echo 'file size (original): ' . round(filesize($source)) . ' bytes<br>';
|
128 |
-
echo 'file size (converted): ' . round(filesize($destination)) . ' bytes<br>';
|
129 |
-
}
|
130 |
-
else {
|
131 |
-
echo 'file size (original): ' . round(filesize($source)/1000) . ' kb<br>';
|
132 |
-
echo 'file size (converted): ' . round(filesize($destination)/1000) . ' kb<br>';
|
133 |
-
}
|
134 |
}
|
135 |
}
|
136 |
|
10 |
error_reporting(E_ALL);
|
11 |
ini_set("display_errors", 1);
|
12 |
|
13 |
+
//require "../wod/webp-convert.inc";
|
14 |
+
require "../vendor/autoload.php";
|
|
|
15 |
|
16 |
use WebPConvert\WebPConvert;
|
17 |
use WebPConvert\Loggers\EchoLogger;
|
71 |
// Set options
|
72 |
$options = [];
|
73 |
foreach ($availOptions as $optionName => $optionType) {
|
74 |
+
//echo $optionName . '<br>';
|
75 |
switch ($optionType) {
|
76 |
case 'string':
|
77 |
if (isset($_GET[$optionName])) {
|
78 |
$options[$optionName] = $_GET[$optionName];
|
79 |
}
|
80 |
break;
|
81 |
+
case 'number':
|
82 |
+
if (isset($_GET[$optionName])) {
|
83 |
+
$options[$optionName] = floatval($_GET[$optionName]);
|
84 |
+
}
|
85 |
+
break;
|
86 |
case 'boolean':
|
87 |
if (isset($_GET[$optionName])) {
|
88 |
$options[$optionName] = ($_GET[$optionName] == 'true');
|
97 |
'options' => getConverterOptionsFromQueryString($converter)
|
98 |
]];
|
99 |
|
100 |
+
//echo '<pre>' . print_r($_GET, true) . '</pre>';
|
101 |
//echo '<pre>' . print_r($options, true) . '</pre>';
|
102 |
|
103 |
function testRun($converter, $source, $destination, $options) {
|
|
|
104 |
|
105 |
try {
|
106 |
$success = WebPConvert::convert($source, $destination, $options, new EchoLogger());
|
108 |
$msg = $e->getMessage();
|
109 |
}
|
110 |
|
|
|
|
|
|
|
111 |
if (!$success) {
|
112 |
+
echo '<h3 class="error">Test conversion failed</h3>';
|
113 |
|
114 |
if (isset($msg)) {
|
115 |
echo '<label>Problem:</label>';
|
118 |
echo '<p class="error-msg">' . $msg . '</p>';
|
119 |
}
|
120 |
} else {
|
121 |
+
//echo '<p>Successfully converted test image</p>';
|
122 |
|
123 |
if (isset($_SERVER['HTTP_ACCEPT']) && (strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') !== false )) {
|
124 |
//echo '<img src="' . $_GET['destinationUrl'] . '" width=48%><br><br>';
|
125 |
echo '<img src="?stream-webp-image=' . $destination . '" width=48%><br><br>';
|
126 |
|
127 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
}
|
129 |
}
|
130 |
|
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
|
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.6.0
|
7 |
* Author: Bjørn Rosell
|
8 |
* Author URI: https://www.bitwise-it.dk
|
9 |
* License: GPL2
|
wod/Binaries/cwebp-fbsd
DELETED
Binary file
|
wod/Binaries/cwebp-linux
DELETED
Binary file
|
wod/Binaries/cwebp-mac12
DELETED
Binary file
|
wod/Binaries/cwebp-sol
DELETED
Binary file
|
wod/Binaries/cwebp.exe
DELETED
Binary file
|
wod/webp-convert-and-serve.inc
DELETED
@@ -1,1615 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
|
4 |
-
namespace WebPConvert\Exceptions;
|
5 |
-
|
6 |
-
class WebPConvertBaseException extends \Exception
|
7 |
-
{
|
8 |
-
}
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
namespace WebPConvert\Loggers;
|
13 |
-
|
14 |
-
abstract class BaseLogger
|
15 |
-
{
|
16 |
-
/*
|
17 |
-
$msg: message to log
|
18 |
-
$style: null | bold | italic
|
19 |
-
*/
|
20 |
-
abstract public function log($msg, $style = '');
|
21 |
-
|
22 |
-
abstract public function ln();
|
23 |
-
|
24 |
-
public function logLn($msg, $style = '')
|
25 |
-
{
|
26 |
-
$this->log($msg, $style);
|
27 |
-
$this->ln();
|
28 |
-
}
|
29 |
-
|
30 |
-
public function logLnLn($msg, $style = '')
|
31 |
-
{
|
32 |
-
$this->logLn($msg, $style);
|
33 |
-
$this->ln();
|
34 |
-
}
|
35 |
-
}
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
namespace WebPConvert;
|
40 |
-
|
41 |
-
use WebPConvert\Converters\ConverterHelper;
|
42 |
-
|
43 |
-
class WebPConvert
|
44 |
-
{
|
45 |
-
|
46 |
-
/*
|
47 |
-
@param (string) $source: Absolute path to image to be converted (no backslashes). Image must be jpeg or png
|
48 |
-
@param (string) $destination: Absolute path (no backslashes)
|
49 |
-
@param (object) $options: Array of named options, such as 'quality' and 'metadata'
|
50 |
-
*/
|
51 |
-
public static function convert($source, $destination, $options = [], $logger = null)
|
52 |
-
{
|
53 |
-
if (!isset($logger)) {
|
54 |
-
$logger = new \WebPConvert\Loggers\VoidLogger();
|
55 |
-
}
|
56 |
-
ConverterHelper::prepareDestinationFolderAndRunCommonValidations($source, $destination);
|
57 |
-
|
58 |
-
$options = array_merge(ConverterHelper::$defaultOptions, $options);
|
59 |
-
|
60 |
-
ConverterHelper::processQualityOption($source, $options, $logger);
|
61 |
-
|
62 |
-
// Force lossless option to true for PNG images
|
63 |
-
if (ConverterHelper::getExtension($source) == 'png') {
|
64 |
-
$options['lossless'] = true;
|
65 |
-
}
|
66 |
-
|
67 |
-
$defaultConverterOptions = $options;
|
68 |
-
$defaultConverterOptions['converters'] = null;
|
69 |
-
|
70 |
-
$firstFailException = null;
|
71 |
-
|
72 |
-
foreach ($options['converters'] as $converter) {
|
73 |
-
if (is_array($converter)) {
|
74 |
-
$converterId = $converter['converter'];
|
75 |
-
$converterOptions = $converter['options'];
|
76 |
-
} else {
|
77 |
-
$converterId = $converter;
|
78 |
-
$converterOptions = [];
|
79 |
-
}
|
80 |
-
|
81 |
-
$converterOptions = array_merge($defaultConverterOptions, $converterOptions);
|
82 |
-
|
83 |
-
try {
|
84 |
-
$logger->logLn('Trying:' . $converterId, 'italic');
|
85 |
-
|
86 |
-
// If quality is different, we must recalculate
|
87 |
-
if ($converterOptions['quality'] != $defaultConverterOptions['quality']) {
|
88 |
-
unset($converterOptions['_calculated_quality']);
|
89 |
-
ConverterHelper::processQualityOption($source, $converterOptions, $logger);
|
90 |
-
}
|
91 |
-
|
92 |
-
ConverterHelper::runConverter($converterId, $source, $destination, $converterOptions, false, $logger);
|
93 |
-
|
94 |
-
// Still here? - well, we did it! - job is done.
|
95 |
-
$logger->logLn('ok', 'bold');
|
96 |
-
return true;
|
97 |
-
} catch (\WebPConvert\Converters\Exceptions\ConverterNotOperationalException $e) {
|
98 |
-
// $logger->logLnLn($e->description . ' : ' . $e->getMessage());
|
99 |
-
$logger->logLnLn($e->getMessage());
|
100 |
-
|
101 |
-
// The converter is not operational.
|
102 |
-
// Well, well, we will just have to try the next, then
|
103 |
-
} catch (\WebPConvert\Converters\Exceptions\ConverterFailedException $e) {
|
104 |
-
$logger->logLnLn($e->getMessage());
|
105 |
-
|
106 |
-
// Converter failed in an anticipated, yet somewhat surprising fashion.
|
107 |
-
// The converter seemed operational - requirements was in order - but it failed anyway.
|
108 |
-
// This is moderately bad.
|
109 |
-
// If some other converter can handle the conversion, we will let this one go.
|
110 |
-
// But if not, we shall throw the exception
|
111 |
-
|
112 |
-
if (!$firstFailException) {
|
113 |
-
$firstFailException = $e;
|
114 |
-
}
|
115 |
-
} catch (\WebPConvert\Converters\Exceptions\ConversionDeclinedException $e) {
|
116 |
-
$logger->logLnLn($e->getMessage());
|
117 |
-
|
118 |
-
// The converter declined.
|
119 |
-
// Gd is for example throwing this, when asked to convert a PNG, but configured not to
|
120 |
-
// We also possibly rethrow this, because it may have come as a surprise to the user
|
121 |
-
// who perhaps only tested jpg
|
122 |
-
if (!$firstFailException) {
|
123 |
-
$firstFailException = $e;
|
124 |
-
}
|
125 |
-
}
|
126 |
-
}
|
127 |
-
|
128 |
-
$logger->logLn('Conversion failed. None of the tried converters are operational', 'bold');
|
129 |
-
|
130 |
-
// No converters could do the job.
|
131 |
-
// If one of them failed moderately bad, rethrow that exception.
|
132 |
-
if ($firstFailException) {
|
133 |
-
throw $firstFailException;
|
134 |
-
}
|
135 |
-
|
136 |
-
return false;
|
137 |
-
}
|
138 |
-
}
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
namespace WebPConvert\Converters;
|
143 |
-
|
144 |
-
//use WebPConvert\Converters\Cwebp;
|
145 |
-
|
146 |
-
use WebPConvert\Exceptions\ConverterNotFoundException;
|
147 |
-
use WebPConvert\Exceptions\CreateDestinationFileException;
|
148 |
-
use WebPConvert\Exceptions\CreateDestinationFolderException;
|
149 |
-
use WebPConvert\Exceptions\InvalidFileExtensionException;
|
150 |
-
use WebPConvert\Exceptions\TargetNotFoundException;
|
151 |
-
|
152 |
-
use WebPConvert\Converters\Exceptions\ConverterNotOperationalException;
|
153 |
-
use WebPConvert\Converters\Exceptions\ConverterFailedException;
|
154 |
-
|
155 |
-
class ConverterHelper
|
156 |
-
{
|
157 |
-
public static $allowedExtensions = ['jpg', 'jpeg', 'png'];
|
158 |
-
|
159 |
-
public static $defaultOptions = [
|
160 |
-
'quality' => 'auto',
|
161 |
-
'max-quality' => 85,
|
162 |
-
'default-quality' => 80,
|
163 |
-
'metadata' => 'none',
|
164 |
-
'method' => 6,
|
165 |
-
'low-memory' => false,
|
166 |
-
'lossless' => false,
|
167 |
-
'converters' => ['cwebp', 'gd', 'imagick']
|
168 |
-
];
|
169 |
-
|
170 |
-
public static function mergeOptions($options, $extraOptions)
|
171 |
-
{
|
172 |
-
return $options;
|
173 |
-
}
|
174 |
-
|
175 |
-
public static function getClassNameOfConverter($converterId)
|
176 |
-
{
|
177 |
-
return 'WebPConvert\\Converters\\' . ucfirst($converterId);
|
178 |
-
}
|
179 |
-
|
180 |
-
|
181 |
-
/* Call the "convert" method on a converter, by id.
|
182 |
-
- but also prepares options (merges in the $extraOptions of the converter),
|
183 |
-
prepares destination folder, and runs some standard validations */
|
184 |
-
public static function runConverter($converterId, $source, $destination, $options = [], $prepareDestinationFolder = true, $logger = null)
|
185 |
-
{
|
186 |
-
if ($prepareDestinationFolder) {
|
187 |
-
ConverterHelper::prepareDestinationFolderAndRunCommonValidations($source, $destination);
|
188 |
-
}
|
189 |
-
|
190 |
-
if (!isset($logger)) {
|
191 |
-
$logger = new \WebPConvert\Loggers\VoidLogger();
|
192 |
-
}
|
193 |
-
|
194 |
-
$className = self::getClassNameOfConverter($converterId);
|
195 |
-
if (!is_callable([$className, 'convert'])) {
|
196 |
-
throw new ConverterNotFoundException();
|
197 |
-
}
|
198 |
-
|
199 |
-
// Prepare options.
|
200 |
-
// - Remove 'converters'
|
201 |
-
$defaultOptions = self::$defaultOptions;
|
202 |
-
unset($defaultOptions['converters']);
|
203 |
-
|
204 |
-
// - Merge defaults of the converters extra options into the standard default options.
|
205 |
-
$defaultOptions = array_merge($defaultOptions, array_column($className::$extraOptions, 'default', 'name'));
|
206 |
-
|
207 |
-
// - Merge $defaultOptions into provided options
|
208 |
-
$options = array_merge($defaultOptions, $options);
|
209 |
-
|
210 |
-
// Individual converters do not accept quality = auto. They need a number.
|
211 |
-
// Change $options['quality'] to number, based on quality of source and several settings
|
212 |
-
|
213 |
-
self::processQualityOption($source, $options, $logger);
|
214 |
-
|
215 |
-
call_user_func(
|
216 |
-
[$className, 'doConvert'],
|
217 |
-
$source,
|
218 |
-
$destination,
|
219 |
-
$options,
|
220 |
-
$logger
|
221 |
-
);
|
222 |
-
|
223 |
-
if (!file_exists($destination)) {
|
224 |
-
throw new ConverterFailedException('Destination file is not there');
|
225 |
-
}
|
226 |
-
}
|
227 |
-
|
228 |
-
/* Try to detect quality of jpeg.
|
229 |
-
If not possible, nothing is returned (null). Otherwise quality is returned (int)
|
230 |
-
*/
|
231 |
-
public static function detectQualityOfJpg($filename)
|
232 |
-
{
|
233 |
-
// Try Imagick extension
|
234 |
-
if (extension_loaded('imagick') && class_exists('Imagick')) {
|
235 |
-
$img = new Imagick($filename);
|
236 |
-
|
237 |
-
// The required function is available as from PECL imagick v2.2.2
|
238 |
-
if (method_exists($img, 'getImageCompressionQuality')) {
|
239 |
-
return $img->getImageCompressionQuality();
|
240 |
-
}
|
241 |
-
}
|
242 |
-
|
243 |
-
if (function_exists('shell_exec')) {
|
244 |
-
|
245 |
-
// Try Imagick
|
246 |
-
$quality = shell_exec("identify -format '%Q' " . $filename);
|
247 |
-
if ($quality) {
|
248 |
-
return intval($quality);
|
249 |
-
}
|
250 |
-
|
251 |
-
// Try GraphicsMagick
|
252 |
-
$quality = shell_exec("gm identify -format '%Q' " . $filename);
|
253 |
-
if ($quality) {
|
254 |
-
return intval($quality);
|
255 |
-
}
|
256 |
-
}
|
257 |
-
}
|
258 |
-
|
259 |
-
public static function processQualityOption($source, &$options, $logger)
|
260 |
-
{
|
261 |
-
if (isset($options['_calculated_quality'])) {
|
262 |
-
return;
|
263 |
-
}
|
264 |
-
if ($options['quality'] == 'auto') {
|
265 |
-
$q = self::detectQualityOfJpg($source);
|
266 |
-
//$logger->log('Quality set to auto... Quality of source: ');
|
267 |
-
if (!$q) {
|
268 |
-
$q = $options['default-quality'];
|
269 |
-
$logger->logLn('Quality of source could not be established (Imagick or GraphicsMagick is required) - Using default instead (' . $options['default-quality'] . ').');
|
270 |
-
|
271 |
-
// this allows the wpc converter to know
|
272 |
-
$options['_quality_could_not_be_detected'] = true;
|
273 |
-
} else {
|
274 |
-
if ($q > $options['max-quality']) {
|
275 |
-
$logger->log('Quality of source is ' . $q . '. This is higher than max-quality, so using that instead (' . $options['max-quality'] . ')');
|
276 |
-
} else {
|
277 |
-
$logger->log('Quality set to same as source: ' . $q);
|
278 |
-
}
|
279 |
-
}
|
280 |
-
$logger->ln();
|
281 |
-
$q = min($q, $options['max-quality']);
|
282 |
-
|
283 |
-
$options['_calculated_quality'] = $q;
|
284 |
-
//$logger->logLn('Using quality: ' . $options['quality']);
|
285 |
-
} else {
|
286 |
-
$logger->logLn('Quality: ' . $options['quality'] . '. Consider setting quality to "auto" instead. It is generally a better idea');
|
287 |
-
$options['_calculated_quality'] = $options['quality'];
|
288 |
-
}
|
289 |
-
$logger->ln();
|
290 |
-
}
|
291 |
-
|
292 |
-
|
293 |
-
public static function getExtension($filePath)
|
294 |
-
{
|
295 |
-
$fileExtension = pathinfo($filePath, PATHINFO_EXTENSION);
|
296 |
-
return strtolower($fileExtension);
|
297 |
-
}
|
298 |
-
|
299 |
-
// Throws an exception if the provided file doesn't exist
|
300 |
-
public static function isValidTarget($filePath)
|
301 |
-
{
|
302 |
-
if (!file_exists($filePath)) {
|
303 |
-
throw new TargetNotFoundException('File or directory not found: ' . $filePath);
|
304 |
-
}
|
305 |
-
|
306 |
-
return true;
|
307 |
-
}
|
308 |
-
|
309 |
-
// Throws an exception if the provided file's extension is invalid
|
310 |
-
public static function isAllowedExtension($filePath)
|
311 |
-
{
|
312 |
-
$fileExtension = pathinfo($filePath, PATHINFO_EXTENSION);
|
313 |
-
if (!in_array(strtolower($fileExtension), self::$allowedExtensions)) {
|
314 |
-
throw new InvalidFileExtensionException('Unsupported file extension: ' . $fileExtension);
|
315 |
-
}
|
316 |
-
|
317 |
-
return true;
|
318 |
-
}
|
319 |
-
|
320 |
-
// Creates folder in provided path & sets correct permissions
|
321 |
-
public static function createWritableFolder($filePath)
|
322 |
-
{
|
323 |
-
$folder = pathinfo($filePath, PATHINFO_DIRNAME);
|
324 |
-
if (!file_exists($folder)) {
|
325 |
-
// TODO: what if this is outside open basedir?
|
326 |
-
// see http://php.net/manual/en/ini.core.php#ini.open-basedir
|
327 |
-
|
328 |
-
// First, we have to figure out which permissions to set.
|
329 |
-
// We want same permissions as parent folder
|
330 |
-
// But which parent? - the parent to the first missing folder
|
331 |
-
|
332 |
-
$parentFolders = explode('/', $folder);
|
333 |
-
$poppedFolders = [];
|
334 |
-
|
335 |
-
while (!(file_exists(implode('/', $parentFolders))) && count($parentFolders) > 0) {
|
336 |
-
array_unshift($poppedFolders, array_pop($parentFolders));
|
337 |
-
}
|
338 |
-
|
339 |
-
// Retrieving permissions of closest existing folder
|
340 |
-
$closestExistingFolder = implode('/', $parentFolders);
|
341 |
-
$permissions = fileperms($closestExistingFolder) & 000777;
|
342 |
-
|
343 |
-
// Trying to create the given folder
|
344 |
-
// Notice: mkdir emits a warning on failure. It would be nice to suppress that, if possible
|
345 |
-
if (!mkdir($folder, $permissions, true)) {
|
346 |
-
throw new CreateDestinationFolderException('Failed creating folder: ' . $folder);
|
347 |
-
}
|
348 |
-
|
349 |
-
|
350 |
-
// `mkdir` doesn't respect permissions, so we have to `chmod` each created subfolder
|
351 |
-
foreach ($poppedFolders as $subfolder) {
|
352 |
-
$closestExistingFolder .= '/' . $subfolder;
|
353 |
-
// Setting directory permissions
|
354 |
-
chmod($folder, $permissions);
|
355 |
-
}
|
356 |
-
}
|
357 |
-
|
358 |
-
// Checks if there's a file in $filePath & if writing permissions are correct
|
359 |
-
if (file_exists($filePath) && !is_writable($filePath)) {
|
360 |
-
throw new CreateDestinationFileException('Cannot overwrite ' . basename($filePath) . ' - check file permissions.');
|
361 |
-
}
|
362 |
-
|
363 |
-
// There's either a rewritable file in $filePath or none at all.
|
364 |
-
// If there is, simply attempt to delete it
|
365 |
-
if (file_exists($filePath) && !unlink($filePath)) {
|
366 |
-
throw new CreateDestinationFileException('Existing file cannot be removed: ' . basename($filePath));
|
367 |
-
}
|
368 |
-
|
369 |
-
return true;
|
370 |
-
}
|
371 |
-
|
372 |
-
public static function prepareDestinationFolderAndRunCommonValidations($source, $destination)
|
373 |
-
{
|
374 |
-
self::isValidTarget($source);
|
375 |
-
self::isAllowedExtension($source);
|
376 |
-
self::createWritableFolder($destination);
|
377 |
-
}
|
378 |
-
|
379 |
-
public static function initCurlForConverter()
|
380 |
-
{
|
381 |
-
if (!extension_loaded('curl')) {
|
382 |
-
throw new ConverterNotOperationalException('Required cURL extension is not available.');
|
383 |
-
}
|
384 |
-
|
385 |
-
if (!function_exists('curl_init')) {
|
386 |
-
throw new ConverterNotOperationalException('Required url_init() function is not available.');
|
387 |
-
}
|
388 |
-
|
389 |
-
if (!function_exists('curl_file_create')) {
|
390 |
-
throw new ConverterNotOperationalException('Required curl_file_create() function is not available (requires PHP > 5.5).');
|
391 |
-
}
|
392 |
-
|
393 |
-
$ch = curl_init();
|
394 |
-
if (!$ch) {
|
395 |
-
throw new ConverterNotOperationalException('Could not initialise cURL.');
|
396 |
-
}
|
397 |
-
return $ch;
|
398 |
-
}
|
399 |
-
}
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
namespace WebPConvert\Converters;
|
404 |
-
|
405 |
-
use WebPConvert\Converters\Exceptions\ConverterNotOperationalException;
|
406 |
-
use WebPConvert\Converters\Exceptions\ConverterFailedException;
|
407 |
-
|
408 |
-
class Cwebp
|
409 |
-
{
|
410 |
-
public static $extraOptions = [
|
411 |
-
[
|
412 |
-
'name' => 'use-nice',
|
413 |
-
'type' => 'boolean',
|
414 |
-
'sensitive' => false,
|
415 |
-
'default' => false,
|
416 |
-
'required' => false
|
417 |
-
],
|
418 |
-
];
|
419 |
-
|
420 |
-
public static function convert($source, $destination, $options = [])
|
421 |
-
{
|
422 |
-
ConverterHelper::runConverter('cwebp', $source, $destination, $options, true);
|
423 |
-
}
|
424 |
-
|
425 |
-
// System paths to look for cwebp binary
|
426 |
-
private static $cwebpDefaultPaths = [
|
427 |
-
'/usr/bin/cwebp',
|
428 |
-
'/usr/local/bin/cwebp',
|
429 |
-
'/usr/gnu/bin/cwebp',
|
430 |
-
'/usr/syno/bin/cwebp'
|
431 |
-
];
|
432 |
-
|
433 |
-
// OS-specific binaries included in this library, along with hashes
|
434 |
-
private static $suppliedBinariesInfo = [
|
435 |
-
'WinNT' => [ 'cwebp.exe', '49e9cb98db30bfa27936933e6fd94d407e0386802cb192800d9fd824f6476873'],
|
436 |
-
'Darwin' => [ 'cwebp-mac12', 'a06a3ee436e375c89dbc1b0b2e8bd7729a55139ae072ed3f7bd2e07de0ebb379'],
|
437 |
-
'SunOS' => [ 'cwebp-sol', '1febaffbb18e52dc2c524cda9eefd00c6db95bc388732868999c0f48deb73b4f'],
|
438 |
-
'FreeBSD' => [ 'cwebp-fbsd', 'e5cbea11c97fadffe221fdf57c093c19af2737e4bbd2cb3cd5e908de64286573'],
|
439 |
-
'Linux' => [ 'cwebp-linux', '916623e5e9183237c851374d969aebdb96e0edc0692ab7937b95ea67dc3b2568']
|
440 |
-
];
|
441 |
-
|
442 |
-
private static function escapeFilename($string)
|
443 |
-
{
|
444 |
-
// Escaping whitespaces & quotes
|
445 |
-
$string = preg_replace('/\s/', '\\ ', $string);
|
446 |
-
$string = filter_var($string, FILTER_SANITIZE_MAGIC_QUOTES);
|
447 |
-
|
448 |
-
// Stripping control characters
|
449 |
-
// see https://stackoverflow.com/questions/12769462/filter-flag-strip-low-vs-filter-flag-strip-high
|
450 |
-
$string = filter_var($string, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
|
451 |
-
|
452 |
-
return $string;
|
453 |
-
}
|
454 |
-
|
455 |
-
// Checks if 'Nice' is available
|
456 |
-
private static function hasNiceSupport()
|
457 |
-
{
|
458 |
-
exec("nice 2>&1", $niceOutput);
|
459 |
-
|
460 |
-
if (is_array($niceOutput) && isset($niceOutput[0])) {
|
461 |
-
if (preg_match('/usage/', $niceOutput[0]) || (preg_match('/^\d+$/', $niceOutput[0]))) {
|
462 |
-
/*
|
463 |
-
* Nice is available - default niceness (+10)
|
464 |
-
* https://www.lifewire.com/uses-of-commands-nice-renice-2201087
|
465 |
-
* https://www.computerhope.com/unix/unice.htm
|
466 |
-
*/
|
467 |
-
|
468 |
-
return true;
|
469 |
-
}
|
470 |
-
|
471 |
-
return false;
|
472 |
-
}
|
473 |
-
}
|
474 |
-
|
475 |
-
//
|
476 |
-
private static function executeBinary($binary, $commandOptions, $useNice, $logger)
|
477 |
-
{
|
478 |
-
$command = ($useNice ? 'nice ' : '') . $binary . ' ' . $commandOptions;
|
479 |
-
|
480 |
-
$logger->logLn('Trying to execute binary:' . $binary);
|
481 |
-
//$logger->logLn();
|
482 |
-
|
483 |
-
exec($command, $output, $returnCode);
|
484 |
-
|
485 |
-
switch ($returnCode) {
|
486 |
-
case 0:
|
487 |
-
$logger->logLn('Success!');
|
488 |
-
break;
|
489 |
-
case 126:
|
490 |
-
$logger->logLn('Permission denied. The user that the command was run with (' . shell_exec('whoami') . ') does not have permission to execute that binary.');
|
491 |
-
break;
|
492 |
-
case 127:
|
493 |
-
$logger->logLn('No binary found at that location');
|
494 |
-
break;
|
495 |
-
default:
|
496 |
-
$logger->logLn('Failed. Return code:' . $returnCode . '. See http://tldp.org/LDP/abs/html/exitcodes.html for failcodes');
|
497 |
-
}
|
498 |
-
return $returnCode;
|
499 |
-
}
|
500 |
-
|
501 |
-
// Although this method is public, do not call directly.
|
502 |
-
public static function doConvert($source, $destination, $options = [], $logger)
|
503 |
-
{
|
504 |
-
$errorMsg = '';
|
505 |
-
// Force lossless option to true for PNG images
|
506 |
-
if (ConverterHelper::getExtension($source) == 'png') {
|
507 |
-
$options['lossless'] = true;
|
508 |
-
}
|
509 |
-
|
510 |
-
if (!function_exists('exec')) {
|
511 |
-
throw new ConverterNotOperationalException('exec() is not enabled.');
|
512 |
-
}
|
513 |
-
|
514 |
-
/*
|
515 |
-
* Prepare cwebp options
|
516 |
-
*/
|
517 |
-
|
518 |
-
// Metadata (all, exif, icc, xmp or none (default))
|
519 |
-
// Comma-separated list of existing metadata to copy from input to output
|
520 |
-
$metadata = '-metadata ' . $options['metadata'];
|
521 |
-
|
522 |
-
// Image quality
|
523 |
-
$quality = '-q ' . $options['_calculated_quality'];
|
524 |
-
|
525 |
-
// Losless PNG conversion
|
526 |
-
$lossless = ($options['lossless'] ? '-lossless' : '');
|
527 |
-
|
528 |
-
// Built-in method option
|
529 |
-
$method = ' -m ' . strval($options['method']);
|
530 |
-
|
531 |
-
|
532 |
-
// TODO:
|
533 |
-
// Why not use -af ? (https://developers.google.com/speed/webp/docs/cwebp)
|
534 |
-
// Would it be possible get a quality similar to source?
|
535 |
-
// It seems so: "identify -format '%Q' yourimage.jpg" (https://stackoverflow.com/questions/2024947/is-it-possible-to-tell-the-quality-level-of-a-jpeg)
|
536 |
-
// -- With -jpeg_like option, or perhaps the -size option
|
537 |
-
|
538 |
-
// Built-in low memory option
|
539 |
-
$lowMemory = '';
|
540 |
-
if ($options['low-memory']) {
|
541 |
-
$lowMemory = '-low_memory';
|
542 |
-
}
|
543 |
-
|
544 |
-
$commandOptionsArray = [
|
545 |
-
$metadata = $metadata,
|
546 |
-
$quality = $quality,
|
547 |
-
$lossless = $lossless,
|
548 |
-
$method = $method,
|
549 |
-
$lowMemory = $lowMemory,
|
550 |
-
$input = self::escapeFilename($source),
|
551 |
-
$output = '-o ' . self::escapeFilename($destination),
|
552 |
-
$stderrRedirect = '2>&1'
|
553 |
-
];
|
554 |
-
|
555 |
-
$useNice = (($options['use-nice']) && self::hasNiceSupport()) ? true : false;
|
556 |
-
|
557 |
-
$commandOptions = implode(' ', $commandOptionsArray);
|
558 |
-
|
559 |
-
|
560 |
-
// Init with common system paths
|
561 |
-
$cwebpPathsToTest = self::$cwebpDefaultPaths;
|
562 |
-
|
563 |
-
// Remove paths that doesn't exist
|
564 |
-
$cwebpPathsToTest = array_filter($cwebpPathsToTest, function ($binary) {
|
565 |
-
//return file_exists($binary);
|
566 |
-
return @is_readable($binary);
|
567 |
-
});
|
568 |
-
|
569 |
-
// Try all common paths that exitst
|
570 |
-
$success = false;
|
571 |
-
foreach ($cwebpPathsToTest as $index => $binary) {
|
572 |
-
$success = (self::executeBinary($binary, $commandOptions, $useNice, $logger) == 0);
|
573 |
-
if ($success) {
|
574 |
-
break;
|
575 |
-
}
|
576 |
-
}
|
577 |
-
if (!$success) {
|
578 |
-
//$logger->logLn('');
|
579 |
-
if (count($cwebpPathsToTest) > 0) {
|
580 |
-
$errorMsg .= 'Found cwebp binaries at these locations: "' . implode('", "', $cwebpPathsToTest) . '". However, executing these failed. ';
|
581 |
-
} else {
|
582 |
-
$errorMsg .= 'Found no cwebp binaries in any common locations. ';
|
583 |
-
}
|
584 |
-
}
|
585 |
-
|
586 |
-
if (!$success) {
|
587 |
-
|
588 |
-
// Try supplied binary (if available for OS, and hash is correct)
|
589 |
-
if (isset(self::$suppliedBinariesInfo[PHP_OS])) {
|
590 |
-
$info = self::$suppliedBinariesInfo[PHP_OS];
|
591 |
-
|
592 |
-
$file = $info[0];
|
593 |
-
$hash = $info[1];
|
594 |
-
|
595 |
-
$binaryFile = __DIR__ . '/Binaries/' . $file;
|
596 |
-
|
597 |
-
// The file should exist, but may have been removed manually.
|
598 |
-
if (file_exists($binaryFile)) {
|
599 |
-
// File exists, now generate its hash
|
600 |
-
$binaryHash = hash_file('sha256', $binaryFile);
|
601 |
-
|
602 |
-
// Throw an exception if binary file checksum & deposited checksum do not match
|
603 |
-
if ($binaryHash != $hash) {
|
604 |
-
//throw new ConverterNotOperationalException('Binary checksum is invalid.');
|
605 |
-
$errorMsg .= 'Binary checksum of supplied binary is invalid! Did you transfer with FTP, but not in binary mode? File:' . $binaryFile . '. Expected checksum: ' . $hash . ' Actual checksum:' . $binaryHash . '. ';
|
606 |
-
} else {
|
607 |
-
$returnCode = self::executeBinary($binaryFile, $commandOptions, $useNice, $logger);
|
608 |
-
if ($returnCode == 0) {
|
609 |
-
$success = true;
|
610 |
-
} else {
|
611 |
-
$errorMsg .= 'Tried executing supplied binary (' . $binaryFile . '), but that failed too: ';
|
612 |
-
switch ($returnCode) {
|
613 |
-
case 126:
|
614 |
-
$errorMsg .= 'Permission denied (user "' . trim(shell_exec('whoami')) . '" does not have permission to execute the binary)';
|
615 |
-
break;
|
616 |
-
default:
|
617 |
-
$errorMsg .= 'Fail code: ' . $returnCode;
|
618 |
-
}
|
619 |
-
}
|
620 |
-
}
|
621 |
-
} else {
|
622 |
-
$errorMsg .= 'Supplied binary not found:' . $binaryFile;
|
623 |
-
}
|
624 |
-
} else {
|
625 |
-
$errorMsg .= 'No supplied binaries found for OS:' . PHP_OS;
|
626 |
-
}
|
627 |
-
}
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
// cwebp sets file permissions to 664 but instead ..
|
632 |
-
// .. $destination's parent folder's permissions should be used (except executable bits)
|
633 |
-
if ($success) {
|
634 |
-
$destinationParent = dirname($destination);
|
635 |
-
$fileStatistics = stat($destinationParent);
|
636 |
-
|
637 |
-
// Apply same permissions as parent folder but strip off the executable bits
|
638 |
-
$permissions = $fileStatistics['mode'] & 0000666;
|
639 |
-
chmod($destination, $permissions);
|
640 |
-
}
|
641 |
-
|
642 |
-
if (!$success) {
|
643 |
-
throw new ConverterNotOperationalException($errorMsg);
|
644 |
-
}
|
645 |
-
}
|
646 |
-
}
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
namespace WebPConvert\Converters;
|
651 |
-
|
652 |
-
use WebPConvert\Converters\Exceptions\ConverterNotOperationalException;
|
653 |
-
use WebPConvert\Converters\Exceptions\ConverterFailedException;
|
654 |
-
|
655 |
-
class Ewww
|
656 |
-
{
|
657 |
-
public static $extraOptions = [
|
658 |
-
[
|
659 |
-
'name' => 'key',
|
660 |
-
'type' => 'string',
|
661 |
-
'sensitive' => true,
|
662 |
-
'default' => '',
|
663 |
-
'required' => true
|
664 |
-
],
|
665 |
-
];
|
666 |
-
|
667 |
-
public static function convert($source, $destination, $options = [])
|
668 |
-
{
|
669 |
-
ConverterHelper::runConverter('ewww', $source, $destination, $options, true);
|
670 |
-
}
|
671 |
-
|
672 |
-
// Although this method is public, do not call directly.
|
673 |
-
public static function doConvert($source, $destination, $options = [], $logger)
|
674 |
-
{
|
675 |
-
if ($options['key'] == '') {
|
676 |
-
throw new ConverterNotOperationalException('Missing API key.');
|
677 |
-
}
|
678 |
-
if (strlen($options['key']) < 20) {
|
679 |
-
throw new ConverterNotOperationalException('Key is invalid. Keys are supposed to be 32 characters long - your key is much shorter');
|
680 |
-
}
|
681 |
-
|
682 |
-
$keyStatus = self::getKeyStatus($options['key']);
|
683 |
-
switch ($keyStatus) {
|
684 |
-
case 'great':
|
685 |
-
break;
|
686 |
-
case 'exceeded':
|
687 |
-
throw new ConverterNotOperationalException('quota has exceeded');
|
688 |
-
break;
|
689 |
-
case 'invalid':
|
690 |
-
throw new ConverterNotOperationalException('key is invalid');
|
691 |
-
break;
|
692 |
-
}
|
693 |
-
|
694 |
-
$ch = ConverterHelper::initCurlForConverter();
|
695 |
-
|
696 |
-
$curlOptions = [
|
697 |
-
'api_key' => $options['key'],
|
698 |
-
'webp' => '1',
|
699 |
-
'file' => curl_file_create($source),
|
700 |
-
'domain' => $_SERVER['HTTP_HOST'],
|
701 |
-
'quality' => $options['_calculated_quality'],
|
702 |
-
'metadata' => ($options['metadata'] == 'none' ? '0' : '1')
|
703 |
-
];
|
704 |
-
|
705 |
-
curl_setopt_array($ch, [
|
706 |
-
CURLOPT_URL => "https://optimize.exactlywww.com/v2/",
|
707 |
-
CURLOPT_HTTPHEADER => [
|
708 |
-
'User-Agent: WebPConvert',
|
709 |
-
'Accept: image/*'
|
710 |
-
],
|
711 |
-
CURLOPT_POSTFIELDS => $curlOptions,
|
712 |
-
CURLOPT_BINARYTRANSFER => true,
|
713 |
-
CURLOPT_RETURNTRANSFER => true,
|
714 |
-
CURLOPT_HEADER => false,
|
715 |
-
CURLOPT_SSL_VERIFYPEER => false
|
716 |
-
]);
|
717 |
-
|
718 |
-
$response = curl_exec($ch);
|
719 |
-
|
720 |
-
if (curl_errno($ch)) {
|
721 |
-
throw new ConverterNotOperationalException(curl_error($ch));
|
722 |
-
}
|
723 |
-
|
724 |
-
// The API does not always return images.
|
725 |
-
// For example, it may return a message such as '{"error":"invalid","t":"exceeded"}
|
726 |
-
// Messages has a http content type of ie 'text/html; charset=UTF-8
|
727 |
-
// Images has application/octet-stream.
|
728 |
-
// So verify that we got an image back.
|
729 |
-
if (curl_getinfo($ch, CURLINFO_CONTENT_TYPE) != 'application/octet-stream') {
|
730 |
-
|
731 |
-
//echo curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
|
732 |
-
curl_close($ch);
|
733 |
-
|
734 |
-
/* May return this: {"error":"invalid","t":"exceeded"} */
|
735 |
-
$responseObj = json_decode($response);
|
736 |
-
if (isset($responseObj->error)) {
|
737 |
-
//echo 'error:' . $responseObj->error . '<br>';
|
738 |
-
//echo $response;
|
739 |
-
//self::blacklistKey($key);
|
740 |
-
//throw new ConverterNotOperationalException('The key is invalid. Blacklisted it!');
|
741 |
-
throw new ConverterNotOperationalException('The key is invalid');
|
742 |
-
}
|
743 |
-
|
744 |
-
throw new ConverterNotOperationalException('ewww api did not return an image. It could be that the key is invalid. Response: ' . $response);
|
745 |
-
}
|
746 |
-
|
747 |
-
// Not sure this can happen. So just in case
|
748 |
-
if ($response == '') {
|
749 |
-
throw new ConverterNotOperationalException('ewww api did not return anything');
|
750 |
-
}
|
751 |
-
|
752 |
-
$success = file_put_contents($destination, $response);
|
753 |
-
|
754 |
-
if (!$success) {
|
755 |
-
throw new ConverterFailedException('Error saving file');
|
756 |
-
}
|
757 |
-
}
|
758 |
-
|
759 |
-
/*
|
760 |
-
public static function blacklistKey($key)
|
761 |
-
{
|
762 |
-
}
|
763 |
-
|
764 |
-
public static function isKeyBlacklisted($key)
|
765 |
-
{
|
766 |
-
}*/
|
767 |
-
|
768 |
-
/**
|
769 |
-
* Return "great", "exceeded" or "invalid"
|
770 |
-
*/
|
771 |
-
public static function getKeyStatus($key)
|
772 |
-
{
|
773 |
-
$ch = ConverterHelper::initCurlForConverter();
|
774 |
-
|
775 |
-
curl_setopt($ch, CURLOPT_URL, "https://optimize.exactlywww.com/verify/");
|
776 |
-
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
777 |
-
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
778 |
-
'api_key' => $key
|
779 |
-
]);
|
780 |
-
|
781 |
-
// The 403 forbidden is avoided with this line.
|
782 |
-
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)');
|
783 |
-
|
784 |
-
$response = curl_exec($ch);
|
785 |
-
// echo $response;
|
786 |
-
if (curl_errno($ch)) {
|
787 |
-
throw new \Exception(curl_error($ch));
|
788 |
-
}
|
789 |
-
curl_close($ch);
|
790 |
-
|
791 |
-
// Possible responses:
|
792 |
-
// “great” = verification successful
|
793 |
-
// “exceeded” = indicates a valid key with no remaining image credits.
|
794 |
-
// an empty response indicates that the key is not valid
|
795 |
-
|
796 |
-
if ($response == '') {
|
797 |
-
return 'invalid';
|
798 |
-
}
|
799 |
-
$responseObj = json_decode($response);
|
800 |
-
if (isset($responseObj->error)) {
|
801 |
-
if ($responseObj->error == 'invalid') {
|
802 |
-
return 'invalid';
|
803 |
-
} else {
|
804 |
-
throw new \Exception('Ewww returned unexpected error: ' . $response);
|
805 |
-
}
|
806 |
-
}
|
807 |
-
if (!isset($responseObj->status)) {
|
808 |
-
throw new \Exception('Ewww returned unexpected response to verify request: ' . $response);
|
809 |
-
}
|
810 |
-
switch ($responseObj->status) {
|
811 |
-
case 'great':
|
812 |
-
case 'exceeded':
|
813 |
-
return $responseObj->status;
|
814 |
-
}
|
815 |
-
throw new \Exception('Ewww returned unexpected status to verify request: "' . $responseObj->status . '"');
|
816 |
-
}
|
817 |
-
|
818 |
-
public static function isWorkingKey($key)
|
819 |
-
{
|
820 |
-
return (self::getKeyStatus($key) == 'great');
|
821 |
-
}
|
822 |
-
|
823 |
-
public static function isValidKey($key)
|
824 |
-
{
|
825 |
-
return (self::getKeyStatus($key) != 'invalid');
|
826 |
-
}
|
827 |
-
|
828 |
-
public static function getQuota($key)
|
829 |
-
{
|
830 |
-
$ch = ConverterHelper::initCurlForConverter();
|
831 |
-
|
832 |
-
curl_setopt($ch, CURLOPT_URL, "https://optimize.exactlywww.com/quota/");
|
833 |
-
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
834 |
-
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
835 |
-
'api_key' => $key
|
836 |
-
]);
|
837 |
-
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)');
|
838 |
-
|
839 |
-
$response = curl_exec($ch);
|
840 |
-
return $response; // ie -830 23. Seems to return empty for invalid keys
|
841 |
-
// or empty
|
842 |
-
//echo $response;
|
843 |
-
}
|
844 |
-
}
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
namespace WebPConvert\Converters;
|
849 |
-
|
850 |
-
use WebPConvert\Converters\Exceptions\ConverterNotOperationalException;
|
851 |
-
use WebPConvert\Converters\Exceptions\ConverterFailedException;
|
852 |
-
use WebPConvert\Converters\Exceptions\ConversionDeclinedException;
|
853 |
-
|
854 |
-
use WebPConvert\Converters\ConverterHelper;
|
855 |
-
|
856 |
-
class Gd
|
857 |
-
{
|
858 |
-
public static $extraOptions = [
|
859 |
-
[
|
860 |
-
'name' => 'skip-pngs',
|
861 |
-
'type' => 'boolean',
|
862 |
-
'sensitive' => false,
|
863 |
-
'default' => true,
|
864 |
-
'required' => false
|
865 |
-
],
|
866 |
-
];
|
867 |
-
|
868 |
-
public static function convert($source, $destination, $options = [])
|
869 |
-
{
|
870 |
-
ConverterHelper::runConverter('gd', $source, $destination, $options, true);
|
871 |
-
}
|
872 |
-
|
873 |
-
// Although this method is public, do not call directly.
|
874 |
-
public static function doConvert($source, $destination, $options = [], $logger)
|
875 |
-
{
|
876 |
-
if (!extension_loaded('gd')) {
|
877 |
-
throw new ConverterNotOperationalException('Required GD extension is not available.');
|
878 |
-
}
|
879 |
-
|
880 |
-
if (!function_exists('imagewebp')) {
|
881 |
-
throw new ConverterNotOperationalException('Required imagewebp() function is not available.');
|
882 |
-
}
|
883 |
-
|
884 |
-
switch (ConverterHelper::getExtension($source)) {
|
885 |
-
case 'png':
|
886 |
-
if (!$options['skip-pngs']) {
|
887 |
-
if (!function_exists('imagecreatefrompng')) {
|
888 |
-
throw new ConverterNotOperationalException('Required imagecreatefrompng() function is not available.');
|
889 |
-
}
|
890 |
-
$image = imagecreatefrompng($source);
|
891 |
-
if (!$image) {
|
892 |
-
throw new ConverterFailedException('imagecreatefrompng("' . $source . '") failed');
|
893 |
-
}
|
894 |
-
} else {
|
895 |
-
throw new ConversionDeclinedException('PNG file skipped. GD is configured not to convert PNGs');
|
896 |
-
}
|
897 |
-
break;
|
898 |
-
default:
|
899 |
-
if (!function_exists('imagecreatefromjpeg')) {
|
900 |
-
throw new ConverterNotOperationalException('Required imagecreatefromjpeg() function is not available.');
|
901 |
-
}
|
902 |
-
$image = imagecreatefromjpeg($source);
|
903 |
-
if (!$image) {
|
904 |
-
throw new ConverterFailedException('imagecreatefromjpeg("' . $source . '") failed');
|
905 |
-
}
|
906 |
-
}
|
907 |
-
|
908 |
-
// Checks if either imagecreatefromjpeg() or imagecreatefrompng() returned false
|
909 |
-
|
910 |
-
$success = imagewebp($image, $destination, $options['_calculated_quality']);
|
911 |
-
|
912 |
-
if (!$success) {
|
913 |
-
throw new ConverterFailedException('Call to imagewebp() failed. Probably failed writing file');
|
914 |
-
}
|
915 |
-
|
916 |
-
/*
|
917 |
-
* This hack solves an `imagewebp` bug
|
918 |
-
* See https://stackoverflow.com/questions/30078090/imagewebp-php-creates-corrupted-webp-files
|
919 |
-
*
|
920 |
-
*/
|
921 |
-
|
922 |
-
if (filesize($destination) % 2 == 1) {
|
923 |
-
file_put_contents($destination, "\0", FILE_APPEND);
|
924 |
-
}
|
925 |
-
|
926 |
-
imagedestroy($image);
|
927 |
-
}
|
928 |
-
}
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
namespace WebPConvert\Converters;
|
933 |
-
|
934 |
-
use WebPConvert\Converters\Exceptions\ConverterNotOperationalException;
|
935 |
-
use WebPConvert\Converters\Exceptions\ConverterFailedException;
|
936 |
-
|
937 |
-
//use WebPConvert\Exceptions\TargetNotFoundException;
|
938 |
-
|
939 |
-
class Imagick
|
940 |
-
{
|
941 |
-
public static $extraOptions = [];
|
942 |
-
|
943 |
-
public static function convert($source, $destination, $options = [])
|
944 |
-
{
|
945 |
-
ConverterHelper::runConverter('imagick', $source, $destination, $options, true);
|
946 |
-
}
|
947 |
-
|
948 |
-
// Although this method is public, do not call directly.
|
949 |
-
public static function doConvert($source, $destination, $options = [], $logger)
|
950 |
-
{
|
951 |
-
if (!extension_loaded('imagick')) {
|
952 |
-
throw new ConverterNotOperationalException('Required iMagick extension is not available.');
|
953 |
-
}
|
954 |
-
|
955 |
-
if (!class_exists('Imagick')) {
|
956 |
-
throw new ConverterNotOperationalException('iMagick is installed, but not correctly. The class Imagick is not available');
|
957 |
-
}
|
958 |
-
|
959 |
-
$im = new \Imagick($source);
|
960 |
-
|
961 |
-
// Throws an exception if iMagick does not support WebP conversion
|
962 |
-
if (!in_array('WEBP', $im->queryFormats())) {
|
963 |
-
throw new ConverterNotOperationalException('iMagick was compiled without WebP support.');
|
964 |
-
}
|
965 |
-
|
966 |
-
$options = array_merge(ConverterHelper::$defaultOptions, $options);
|
967 |
-
|
968 |
-
// Force lossless option to true for PNG images
|
969 |
-
if (ConverterHelper::getExtension($source) == 'png') {
|
970 |
-
$options['lossless'] = true;
|
971 |
-
}
|
972 |
-
|
973 |
-
$im->setImageFormat('WEBP');
|
974 |
-
|
975 |
-
/*
|
976 |
-
* More about iMagick's WebP options:
|
977 |
-
* http://www.imagemagick.org/script/webp.php
|
978 |
-
* https://developers.google.com/speed/webp/docs/cwebp
|
979 |
-
* https://stackoverflow.com/questions/37711492/imagemagick-specific-webp-calls-in-php
|
980 |
-
*/
|
981 |
-
|
982 |
-
// TODO: We could easily support all webp options with a loop
|
983 |
-
$im->setOption('webp:method', strval($options['method']));
|
984 |
-
$im->setOption('webp:low-memory', strval($options['low-memory']));
|
985 |
-
$im->setOption('webp:lossless', strval($options['lossless']));
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
$im->setImageCompressionQuality($options['_calculated_quality']);
|
990 |
-
|
991 |
-
// TODO:
|
992 |
-
// Should we set alpha channel for PNG's like suggested here:
|
993 |
-
// https://gauntface.com/blog/2014/09/02/webp-support-with-imagemagick-and-php ??
|
994 |
-
// It seems that alpha channel works without... (at least I see completely transparerent pixels)
|
995 |
-
|
996 |
-
// TODO: Check out other iMagick methods, see http://php.net/manual/de/imagick.writeimage.php#114714
|
997 |
-
// 1. file_put_contents($destination, $im)
|
998 |
-
// 2. $im->writeImage($destination)
|
999 |
-
$success = $im->writeImageFile(fopen($destination, 'wb'));
|
1000 |
-
|
1001 |
-
if (!$success) {
|
1002 |
-
throw new ConverterFailedException('Failed writing file');
|
1003 |
-
}
|
1004 |
-
}
|
1005 |
-
}
|
1006 |
-
|
1007 |
-
|
1008 |
-
|
1009 |
-
namespace WebPConvert\Converters;
|
1010 |
-
|
1011 |
-
use WebPConvert\Converters\Exceptions\ConverterNotOperationalException;
|
1012 |
-
use WebPConvert\Converters\Exceptions\ConverterFailedException;
|
1013 |
-
|
1014 |
-
class Wpc
|
1015 |
-
{
|
1016 |
-
public static $extraOptions = [
|
1017 |
-
[
|
1018 |
-
'name' => 'secret',
|
1019 |
-
'type' => 'string',
|
1020 |
-
'sensitive' => true,
|
1021 |
-
'default' => 'my dog is white',
|
1022 |
-
'required' => true
|
1023 |
-
],
|
1024 |
-
[
|
1025 |
-
'name' => 'url',
|
1026 |
-
'type' => 'string',
|
1027 |
-
'sensitive' => true,
|
1028 |
-
'default' => '',
|
1029 |
-
'required' => true
|
1030 |
-
],
|
1031 |
-
];
|
1032 |
-
|
1033 |
-
public static function convert($source, $destination, $options = [])
|
1034 |
-
{
|
1035 |
-
ConverterHelper::runConverter('wpc', $source, $destination, $options, true);
|
1036 |
-
}
|
1037 |
-
|
1038 |
-
// Although this method is public, do not call directly.
|
1039 |
-
public static function doConvert($source, $destination, $options = [], $logger)
|
1040 |
-
{
|
1041 |
-
if ($options['url'] == '') {
|
1042 |
-
throw new ConverterNotOperationalException('Missing URL. You must install WebpConvertCloudService on a server, and supply url');
|
1043 |
-
}
|
1044 |
-
|
1045 |
-
if (!extension_loaded('curl')) {
|
1046 |
-
throw new ConverterNotOperationalException('Required cURL extension is not available.');
|
1047 |
-
}
|
1048 |
-
|
1049 |
-
if (!function_exists('curl_init')) {
|
1050 |
-
throw new ConverterNotOperationalException('Required url_init() function is not available.');
|
1051 |
-
}
|
1052 |
-
|
1053 |
-
if (!function_exists('curl_file_create')) {
|
1054 |
-
throw new ConverterNotOperationalException('Required curl_file_create() function is not available (requires PHP > 5.5).');
|
1055 |
-
}
|
1056 |
-
|
1057 |
-
// Got some code here:
|
1058 |
-
// https://coderwall.com/p/v4ps1a/send-a-file-via-post-with-curl-and-php
|
1059 |
-
|
1060 |
-
$ch = curl_init();
|
1061 |
-
if (!$ch) {
|
1062 |
-
throw new ConverterNotOperationalException('Could not initialise cURL.');
|
1063 |
-
}
|
1064 |
-
|
1065 |
-
$optionsToSend = $options;
|
1066 |
-
|
1067 |
-
if (isset($options['_quality_could_not_be_detected'])) {
|
1068 |
-
// quality was set to "auto", but we could not meassure the quality of the jpeg locally
|
1069 |
-
// Ask the cloud service to do it, rather than using what we came up with.
|
1070 |
-
$optionsToSend['quality'] = 'auto';
|
1071 |
-
} else {
|
1072 |
-
$optionsToSend['quality'] = $options['_calculated_quality'];
|
1073 |
-
}
|
1074 |
-
|
1075 |
-
unset($optionsToSend['converters']);
|
1076 |
-
unset($optionsToSend['secret']);
|
1077 |
-
unset($optionsToSend['_quality_could_not_be_detected']);
|
1078 |
-
unset($optionsToSend['_calculated_quality']);
|
1079 |
-
|
1080 |
-
curl_setopt_array($ch, [
|
1081 |
-
CURLOPT_URL => $options['url'],
|
1082 |
-
CURLOPT_POST => 1,
|
1083 |
-
CURLOPT_POSTFIELDS => [
|
1084 |
-
'file' => curl_file_create($source),
|
1085 |
-
'hash' => md5(md5_file($source) . $options['secret']),
|
1086 |
-
'options' => json_encode($optionsToSend)
|
1087 |
-
],
|
1088 |
-
CURLOPT_BINARYTRANSFER => true,
|
1089 |
-
CURLOPT_RETURNTRANSFER => true,
|
1090 |
-
CURLOPT_HEADER => false,
|
1091 |
-
CURLOPT_SSL_VERIFYPEER => false
|
1092 |
-
]);
|
1093 |
-
|
1094 |
-
$response = curl_exec($ch);
|
1095 |
-
|
1096 |
-
if (curl_errno($ch)) {
|
1097 |
-
throw new ConverterNotOperationalException(curl_error($ch));
|
1098 |
-
}
|
1099 |
-
|
1100 |
-
// The WPC cloud service either returns an image or an error message
|
1101 |
-
// Images has application/octet-stream.
|
1102 |
-
|
1103 |
-
// TODO: Check for 404 response, and handle that here
|
1104 |
-
|
1105 |
-
// Verify that we got an image back.
|
1106 |
-
if (curl_getinfo($ch, CURLINFO_CONTENT_TYPE) != 'application/octet-stream') {
|
1107 |
-
curl_close($ch);
|
1108 |
-
throw new ConverterFailedException($response);
|
1109 |
-
//throw new ConverterNotOperationalException($response);
|
1110 |
-
}
|
1111 |
-
|
1112 |
-
$success = file_put_contents($destination, $response);
|
1113 |
-
curl_close($ch);
|
1114 |
-
|
1115 |
-
if (!$success) {
|
1116 |
-
throw new ConverterFailedException('Error saving file');
|
1117 |
-
}
|
1118 |
-
/*
|
1119 |
-
$curlOptions = [
|
1120 |
-
'api_key' => $options['key'],
|
1121 |
-
'webp' => '1',
|
1122 |
-
'file' => curl_file_create($source),
|
1123 |
-
'domain' => $_SERVER['HTTP_HOST'],
|
1124 |
-
'quality' => $options['quality'],
|
1125 |
-
'metadata' => ($options['metadata'] == 'none' ? '0' : '1')
|
1126 |
-
];
|
1127 |
-
|
1128 |
-
curl_setopt_array($ch, [
|
1129 |
-
CURLOPT_URL => "https://optimize.exactlywww.com/v2/",
|
1130 |
-
CURLOPT_HTTPHEADER => [
|
1131 |
-
'User-Agent: WebPConvert',
|
1132 |
-
'Accept: image/*'
|
1133 |
-
],
|
1134 |
-
CURLOPT_POSTFIELDS => $curlOptions,
|
1135 |
-
CURLOPT_BINARYTRANSFER => true,
|
1136 |
-
CURLOPT_RETURNTRANSFER => true,
|
1137 |
-
CURLOPT_HEADER => false,
|
1138 |
-
CURLOPT_SSL_VERIFYPEER => false
|
1139 |
-
]);*/
|
1140 |
-
}
|
1141 |
-
}
|
1142 |
-
|
1143 |
-
|
1144 |
-
|
1145 |
-
namespace WebPConvert\Exceptions;
|
1146 |
-
|
1147 |
-
use WebPConvert\Exceptions\WebPConvertBaseException;
|
1148 |
-
|
1149 |
-
class ConverterNotFoundException extends WebPConvertBaseException
|
1150 |
-
{
|
1151 |
-
public $description = 'The converter does not exist.';
|
1152 |
-
}
|
1153 |
-
|
1154 |
-
|
1155 |
-
|
1156 |
-
namespace WebPConvert\Exceptions;
|
1157 |
-
|
1158 |
-
use WebPConvert\Exceptions\WebPConvertBaseException;
|
1159 |
-
|
1160 |
-
class CreateDestinationFileException extends WebPConvertBaseException
|
1161 |
-
{
|
1162 |
-
public $description = 'The converter could not create destination file. Check file permisions!';
|
1163 |
-
}
|
1164 |
-
|
1165 |
-
|
1166 |
-
|
1167 |
-
namespace WebPConvert\Exceptions;
|
1168 |
-
|
1169 |
-
use WebPConvert\Exceptions\WebPConvertBaseException;
|
1170 |
-
|
1171 |
-
class CreateDestinationFolderException extends WebPConvertBaseException
|
1172 |
-
{
|
1173 |
-
public $description = 'The converter could not create destination folder. Check file permisions!';
|
1174 |
-
}
|
1175 |
-
|
1176 |
-
|
1177 |
-
|
1178 |
-
namespace WebPConvert\Exceptions;
|
1179 |
-
|
1180 |
-
use WebPConvert\Exceptions\WebPConvertBaseException;
|
1181 |
-
|
1182 |
-
class InvalidFileExtensionException extends WebPConvertBaseException
|
1183 |
-
{
|
1184 |
-
public $description = 'The converter does not accept the file extension';
|
1185 |
-
}
|
1186 |
-
|
1187 |
-
|
1188 |
-
|
1189 |
-
namespace WebPConvert\Exceptions;
|
1190 |
-
|
1191 |
-
use WebPConvert\Exceptions\WebPConvertBaseException;
|
1192 |
-
|
1193 |
-
class TargetNotFoundException extends WebPConvertBaseException
|
1194 |
-
{
|
1195 |
-
public $description = 'The converter could not locate source file';
|
1196 |
-
}
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
1200 |
-
namespace WebPConvert\Converters\Exceptions;
|
1201 |
-
|
1202 |
-
use WebPConvert\Exceptions\WebPConvertBaseException;
|
1203 |
-
|
1204 |
-
class ConversionDeclinedException extends WebPConvertBaseException
|
1205 |
-
{
|
1206 |
-
public $description = 'The converter declined converting';
|
1207 |
-
}
|
1208 |
-
|
1209 |
-
|
1210 |
-
|
1211 |
-
namespace WebPConvert\Converters\Exceptions;
|
1212 |
-
|
1213 |
-
use WebPConvert\Exceptions\WebPConvertBaseException;
|
1214 |
-
|
1215 |
-
class ConverterFailedException extends WebPConvertBaseException
|
1216 |
-
{
|
1217 |
-
public $description = 'The converter failed converting, although requirements seemed to be met';
|
1218 |
-
}
|
1219 |
-
|
1220 |
-
|
1221 |
-
|
1222 |
-
namespace WebPConvert\Converters\Exceptions;
|
1223 |
-
|
1224 |
-
use WebPConvert\Exceptions\WebPConvertBaseException;
|
1225 |
-
|
1226 |
-
class ConverterNotOperationalException extends WebPConvertBaseException
|
1227 |
-
{
|
1228 |
-
public $description = 'The converter is not operational';
|
1229 |
-
}
|
1230 |
-
|
1231 |
-
|
1232 |
-
|
1233 |
-
namespace WebPConvert\Loggers;
|
1234 |
-
|
1235 |
-
class EchoLogger extends BaseLogger
|
1236 |
-
{
|
1237 |
-
public function log($msg, $style = '')
|
1238 |
-
{
|
1239 |
-
if ($style == 'bold') {
|
1240 |
-
echo '<b>' . $msg . '</b>';
|
1241 |
-
} elseif ($style == 'italic') {
|
1242 |
-
echo '<i>' . $msg . '</i>';
|
1243 |
-
} else {
|
1244 |
-
echo $msg;
|
1245 |
-
}
|
1246 |
-
}
|
1247 |
-
|
1248 |
-
public function ln()
|
1249 |
-
{
|
1250 |
-
echo '<br>';
|
1251 |
-
}
|
1252 |
-
}
|
1253 |
-
|
1254 |
-
|
1255 |
-
|
1256 |
-
namespace WebPConvert\Loggers;
|
1257 |
-
|
1258 |
-
class VoidLogger extends BaseLogger
|
1259 |
-
{
|
1260 |
-
public function log($msg, $style = '')
|
1261 |
-
{
|
1262 |
-
}
|
1263 |
-
|
1264 |
-
public function ln()
|
1265 |
-
{
|
1266 |
-
}
|
1267 |
-
}
|
1268 |
-
|
1269 |
-
|
1270 |
-
|
1271 |
-
namespace WebPConvertAndServe;
|
1272 |
-
use WebPConvert\Loggers\BaseLogger;
|
1273 |
-
|
1274 |
-
class BufferLogger extends BaseLogger
|
1275 |
-
{
|
1276 |
-
public $entries = array();
|
1277 |
-
|
1278 |
-
public function log($msg, $style = '')
|
1279 |
-
{
|
1280 |
-
$this->entries[] = [$msg, $style];
|
1281 |
-
}
|
1282 |
-
|
1283 |
-
public function ln()
|
1284 |
-
{
|
1285 |
-
$this->entries[] = '';
|
1286 |
-
}
|
1287 |
-
|
1288 |
-
public function getHtml()
|
1289 |
-
{
|
1290 |
-
$html = '';
|
1291 |
-
foreach ($this->entries as $entry) {
|
1292 |
-
if ($entry == '') {
|
1293 |
-
$html .= '<br>';
|
1294 |
-
} else {
|
1295 |
-
list($msg, $style) = $entry;
|
1296 |
-
|
1297 |
-
if ($style == 'bold') {
|
1298 |
-
$html .= '<b>' . $msg . '</b>';
|
1299 |
-
} elseif ($style == 'italic') {
|
1300 |
-
$html .= '<i>' . $msg . '</i>';
|
1301 |
-
} else {
|
1302 |
-
$html .= $msg;
|
1303 |
-
}
|
1304 |
-
}
|
1305 |
-
}
|
1306 |
-
return $html;
|
1307 |
-
}
|
1308 |
-
|
1309 |
-
public function getText($newLineChar = ' ')
|
1310 |
-
{
|
1311 |
-
$text = '';
|
1312 |
-
foreach ($this->entries as $entry) {
|
1313 |
-
if ($entry == '') {
|
1314 |
-
if (substr($text, -2) != '. ') {
|
1315 |
-
$text .= '. ';
|
1316 |
-
}
|
1317 |
-
} else {
|
1318 |
-
list($msg, $style) = $entry;
|
1319 |
-
$text .= $msg;
|
1320 |
-
}
|
1321 |
-
}
|
1322 |
-
|
1323 |
-
return $text;
|
1324 |
-
}
|
1325 |
-
}
|
1326 |
-
|
1327 |
-
|
1328 |
-
namespace WebPConvertAndServe;
|
1329 |
-
|
1330 |
-
use WebPConvert\WebPConvert;
|
1331 |
-
use WebPConvertAndServe\BufferLogger;
|
1332 |
-
use WebPConvert\Converters\ConverterHelper;
|
1333 |
-
//use WebPConvert\Loggers\EchoLogger;
|
1334 |
-
|
1335 |
-
class WebPConvertAndServe
|
1336 |
-
{
|
1337 |
-
public static $CONVERTED_IMAGE = 1;
|
1338 |
-
public static $ORIGINAL = -1;
|
1339 |
-
public static $HTTP_404 = -2;
|
1340 |
-
public static $REPORT_AS_IMAGE = -3;
|
1341 |
-
public static $REPORT = -4;
|
1342 |
-
|
1343 |
-
public static $defaultOptions = [
|
1344 |
-
'fail' => 'original',
|
1345 |
-
'critical-fail' => '404',
|
1346 |
-
];
|
1347 |
-
|
1348 |
-
private static function serve404()
|
1349 |
-
{
|
1350 |
-
$protocol = isset($_SERVER["SERVER_PROTOCOL"]) ? $_SERVER["SERVER_PROTOCOL"] : 'HTTP/1.0';
|
1351 |
-
header($protocol . " 404 Not Found");
|
1352 |
-
}
|
1353 |
-
|
1354 |
-
private static function serveOriginal($source)
|
1355 |
-
{
|
1356 |
-
// Prevent caching image
|
1357 |
-
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
1358 |
-
header("Cache-Control: post-check=0, pre-check=0", false);
|
1359 |
-
header("Pragma: no-cache");
|
1360 |
-
|
1361 |
-
$arr = explode('.', $source);
|
1362 |
-
$ext = array_pop($arr);
|
1363 |
-
switch (strtolower($ext)) {
|
1364 |
-
case 'jpg':
|
1365 |
-
case 'jpeg':
|
1366 |
-
header('Content-type: image/jpeg');
|
1367 |
-
break;
|
1368 |
-
case 'png':
|
1369 |
-
header('Content-type: image/png');
|
1370 |
-
break;
|
1371 |
-
}
|
1372 |
-
readfile($source);
|
1373 |
-
}
|
1374 |
-
|
1375 |
-
private static function serveErrorMessageImage($msg)
|
1376 |
-
{
|
1377 |
-
// Generate image containing error message
|
1378 |
-
header('Content-type: image/gif');
|
1379 |
-
|
1380 |
-
// Prevent caching image
|
1381 |
-
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
1382 |
-
header("Cache-Control: post-check=0, pre-check=0", false);
|
1383 |
-
header("Pragma: no-cache");
|
1384 |
-
|
1385 |
-
$image = imagecreatetruecolor(620, 200);
|
1386 |
-
imagestring($image, 1, 5, 5, $msg, imagecolorallocate($image, 233, 214, 291));
|
1387 |
-
// echo imagewebp($image);
|
1388 |
-
echo imagegif($image);
|
1389 |
-
imagedestroy($image);
|
1390 |
-
}
|
1391 |
-
|
1392 |
-
/**
|
1393 |
-
* @depreciated
|
1394 |
-
*/
|
1395 |
-
public static function convertAndServeImage($source, $destination, $options, $failAction, $criticalFailAction, $debug = false)
|
1396 |
-
{
|
1397 |
-
if ($debug) {
|
1398 |
-
error_reporting(E_ALL);
|
1399 |
-
ini_set('display_errors', 'On');
|
1400 |
-
} else {
|
1401 |
-
ini_set('display_errors', 'Off');
|
1402 |
-
}
|
1403 |
-
|
1404 |
-
$options['fail'] = $failAction;
|
1405 |
-
$options['critical-fail'] = $criticalFailAction;
|
1406 |
-
|
1407 |
-
return self::convertAndServe($source, $destination, $options);
|
1408 |
-
}
|
1409 |
-
|
1410 |
-
/**
|
1411 |
-
* Main method
|
1412 |
-
*/
|
1413 |
-
public static function convertAndServe($source, $destination, $options)
|
1414 |
-
{
|
1415 |
-
$options = array_merge(self::$defaultOptions, $options);
|
1416 |
-
|
1417 |
-
$failCodes = [
|
1418 |
-
"original" => -1,
|
1419 |
-
"404" => -2,
|
1420 |
-
"report-as-image" => -3,
|
1421 |
-
"report" => -4,
|
1422 |
-
];
|
1423 |
-
|
1424 |
-
$failAction = $options['fail'];
|
1425 |
-
$criticalFailAction = $options['critical-fail'];
|
1426 |
-
|
1427 |
-
if (is_string($failAction)) {
|
1428 |
-
$failAction = $failCodes[$failAction];
|
1429 |
-
}
|
1430 |
-
if (is_string($criticalFailAction)) {
|
1431 |
-
$criticalFailAction = $failCodes[$criticalFailAction];
|
1432 |
-
}
|
1433 |
-
|
1434 |
-
$criticalFail = false;
|
1435 |
-
$success = false;
|
1436 |
-
$bufferLogger = new BufferLogger();
|
1437 |
-
|
1438 |
-
try {
|
1439 |
-
$success = WebPConvert::convert($source, $destination, $options, $bufferLogger);
|
1440 |
-
|
1441 |
-
if ($success) {
|
1442 |
-
$status = 'Success';
|
1443 |
-
$msg = 'Success';
|
1444 |
-
} else {
|
1445 |
-
$status = 'Failure (no converters are operational)';
|
1446 |
-
$msg = 'No converters are operational';
|
1447 |
-
}
|
1448 |
-
} catch (\WebPConvert\Exceptions\InvalidFileExtensionException $e) {
|
1449 |
-
$criticalFail = true;
|
1450 |
-
$status = 'Failure (invalid file extension)';
|
1451 |
-
$msg = $e->getMessage();
|
1452 |
-
} catch (\WebPConvert\Exceptions\TargetNotFoundException $e) {
|
1453 |
-
$criticalFail = true;
|
1454 |
-
$status = 'Failure (target file not found)';
|
1455 |
-
$msg = $e->getMessage();
|
1456 |
-
} catch (\WebPConvert\Converters\Exceptions\ConverterFailedException $e) {
|
1457 |
-
// No converters could convert the image. At least one converter failed, even though it appears to be operational
|
1458 |
-
$status = 'Failure (no converters could convert the image)';
|
1459 |
-
$msg = $e->getMessage();
|
1460 |
-
} catch (\WebPConvert\Converters\Exceptions\ConversionDeclinedException $e) {
|
1461 |
-
// (no converters could convert the image. At least one converter declined
|
1462 |
-
$status = 'Failure (no converters could/wanted to convert the image)';
|
1463 |
-
$msg = $e->getMessage();
|
1464 |
-
} catch (\WebPConvert\Exceptions\ConverterNotFoundException $e) {
|
1465 |
-
$status = 'Failure (a converter was not found!)';
|
1466 |
-
$msg = $e->getMessage();
|
1467 |
-
} catch (\WebPConvert\Exceptions\CreateDestinationFileException $e) {
|
1468 |
-
$status = 'Failure (cannot create destination file)';
|
1469 |
-
$msg = $e->getMessage();
|
1470 |
-
} catch (\WebPConvert\Exceptions\CreateDestinationFolderException $e) {
|
1471 |
-
$status = 'Failure (cannot create destination folder)';
|
1472 |
-
$msg = $e->getMessage();
|
1473 |
-
} catch (\Exception $e) {
|
1474 |
-
$status = 'Failure (an unanticipated exception was thrown)';
|
1475 |
-
$msg = $e->getMessage();
|
1476 |
-
}
|
1477 |
-
|
1478 |
-
$optionsForPrint = [];
|
1479 |
-
foreach (self::getPrintableOptions($options) as $optionName => $optionValue) {
|
1480 |
-
if ($optionName == 'converters') {
|
1481 |
-
$converterNames = [];
|
1482 |
-
$extraConvertOptions = [];
|
1483 |
-
foreach ($optionValue as $converter) {
|
1484 |
-
if (is_array($converter)) {
|
1485 |
-
$converterNames[] = $converter['converter'];
|
1486 |
-
if (isset($converter['options'])) {
|
1487 |
-
$extraConvertOptions[$converter['converter']] = $converter['options'];
|
1488 |
-
}
|
1489 |
-
} else {
|
1490 |
-
$converterNames[] = $converter;
|
1491 |
-
}
|
1492 |
-
}
|
1493 |
-
$optionsForPrint[] = 'converters:' . implode(',', $converterNames);
|
1494 |
-
foreach ($extraConvertOptions as $converter => $extraOptions) {
|
1495 |
-
$opt = [];
|
1496 |
-
foreach ($extraOptions as $oName => $oValue) {
|
1497 |
-
$opt[] = $oName . ':"' . $oValue . '"';
|
1498 |
-
}
|
1499 |
-
$optionsForPrint[] = $converter . ' options:(' . implode($opt, ', ') . ')';
|
1500 |
-
}
|
1501 |
-
} else {
|
1502 |
-
$optionsForPrint[] = $optionName . ':' . $optionValue ;
|
1503 |
-
}
|
1504 |
-
|
1505 |
-
}
|
1506 |
-
|
1507 |
-
header('X-WebP-Convert-And-Serve-Options:' . implode('. ', $optionsForPrint));
|
1508 |
-
|
1509 |
-
header('X-WebP-Convert-And-Serve-Status: ' . $status);
|
1510 |
-
|
1511 |
-
// Next line is commented out, because we need to be absolute sure that the details does not violate header syntax
|
1512 |
-
// We could either try to filter it, or we could change WebPConvert, such that it only provides safe texts.
|
1513 |
-
// header('X-WebP-Convert-And-Serve-Details: ' . $bufferLogger->getText());
|
1514 |
-
|
1515 |
-
if ($success) {
|
1516 |
-
header('Content-type: image/webp');
|
1517 |
-
// Should we add Content-Length header?
|
1518 |
-
// header('Content-Length: ' . filesize($file));
|
1519 |
-
readfile($destination);
|
1520 |
-
return self::$CONVERTED_IMAGE;
|
1521 |
-
} else {
|
1522 |
-
$action = ($criticalFail ? $criticalFailAction : $failAction);
|
1523 |
-
|
1524 |
-
switch ($action) {
|
1525 |
-
case WebPConvertAndServe::$ORIGINAL:
|
1526 |
-
self::serveOriginal($source);
|
1527 |
-
break;
|
1528 |
-
case WebPConvertAndServe::$HTTP_404:
|
1529 |
-
self::serve404();
|
1530 |
-
break;
|
1531 |
-
case WebPConvertAndServe::$REPORT_AS_IMAGE:
|
1532 |
-
self::serveErrorMessageImage($status . '. ' . $msg);
|
1533 |
-
break;
|
1534 |
-
case WebPConvertAndServe::$REPORT:
|
1535 |
-
echo '<h1>' . $status . '</h1>';
|
1536 |
-
echo $msg;
|
1537 |
-
echo '<p>This is how conversion process went:</p>' . $bufferLogger->getHtml();
|
1538 |
-
break;
|
1539 |
-
}
|
1540 |
-
return $action;
|
1541 |
-
}
|
1542 |
-
}
|
1543 |
-
|
1544 |
-
/* Hides sensitive options */
|
1545 |
-
private static function getPrintableOptions($options)
|
1546 |
-
{
|
1547 |
-
|
1548 |
-
$printable_options = [];
|
1549 |
-
|
1550 |
-
// (psst: the is_callable check is needed in order to work with WebPConvert v1.0)
|
1551 |
-
if (is_callable('ConverterHelper', 'getClassNameOfConverter')) {
|
1552 |
-
|
1553 |
-
$printable_options = $options;
|
1554 |
-
if (isset($printable_options['converters'])) {
|
1555 |
-
foreach ($printable_options['converters'] as &$converter) {
|
1556 |
-
if (is_array($converter)) {
|
1557 |
-
//echo '::' . $converter['converter'] . '<br>';
|
1558 |
-
$className = ConverterHelper::getClassNameOfConverter($converter['converter']);
|
1559 |
-
|
1560 |
-
// (pstt: the isset check is needed in order to work with WebPConvert v1.0)
|
1561 |
-
if (isset($className::$extraOptions)) {
|
1562 |
-
foreach ($className::$extraOptions as $extraOption) {
|
1563 |
-
if ($extraOption['sensitive']) {
|
1564 |
-
if (isset($converter['options'][$extraOption['name']])) {
|
1565 |
-
$converter['options'][$extraOption['name']] = '*******';
|
1566 |
-
}
|
1567 |
-
}
|
1568 |
-
}
|
1569 |
-
}
|
1570 |
-
}
|
1571 |
-
}
|
1572 |
-
}
|
1573 |
-
}
|
1574 |
-
return $printable_options;
|
1575 |
-
}
|
1576 |
-
|
1577 |
-
public static function convertAndReport($source, $destination, $options)
|
1578 |
-
{
|
1579 |
-
error_reporting(E_ALL);
|
1580 |
-
ini_set('display_errors', 'On');
|
1581 |
-
|
1582 |
-
echo '<html><style>td {vertical-align: top} table {color: #666}</style>';
|
1583 |
-
echo '<body><table>';
|
1584 |
-
echo '<tr><td><i>source:</i></td><td>' . $source . '</td></tr>';
|
1585 |
-
echo '<tr><td><i>destination:</i></td><td>' . $destination . '<td></tr>';
|
1586 |
-
|
1587 |
-
echo '<tr><td><i>options:</i></td><td>' . print_r(self::getPrintableOptions($options), true) . '</td></tr>';
|
1588 |
-
echo '</table>';
|
1589 |
-
|
1590 |
-
// TODO:
|
1591 |
-
// We could display warning if unknown options are set
|
1592 |
-
// but that requires that WebPConvert also describes its general options
|
1593 |
-
|
1594 |
-
echo '<br>';
|
1595 |
-
|
1596 |
-
try {
|
1597 |
-
$echoLogger = new \WebPConvert\Loggers\EchoLogger();
|
1598 |
-
$success = WebPConvert::convert($source, $destination, $options, $echoLogger);
|
1599 |
-
} catch (\Exception $e) {
|
1600 |
-
$success = false;
|
1601 |
-
|
1602 |
-
$msg = $e->getMessage();
|
1603 |
-
|
1604 |
-
echo '<b>' . $msg . '</b>';
|
1605 |
-
exit;
|
1606 |
-
}
|
1607 |
-
|
1608 |
-
if ($success) {
|
1609 |
-
//echo 'ok';
|
1610 |
-
} else {
|
1611 |
-
echo '<b>Conversion failed. None of the tried converters are operational</b>';
|
1612 |
-
}
|
1613 |
-
echo '</body></html>';
|
1614 |
-
}
|
1615 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wod/webp-on-demand.inc
DELETED
@@ -1,135 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
|
4 |
-
namespace WebPOnDemand;
|
5 |
-
|
6 |
-
class WebPOnDemand
|
7 |
-
{
|
8 |
-
public static $defaultOptions = [
|
9 |
-
'show-report' => false,
|
10 |
-
'reconvert' => false,
|
11 |
-
'original' => false,
|
12 |
-
'add-x-webp-on-demand-headers' => true,
|
13 |
-
'add-vary-header' => true,
|
14 |
-
];
|
15 |
-
|
16 |
-
private static function serveOriginal($source)
|
17 |
-
{
|
18 |
-
// Serve original image
|
19 |
-
$arr = explode('.', $source);
|
20 |
-
$ext = array_pop($arr);
|
21 |
-
switch (strtolower($ext)) {
|
22 |
-
case 'jpg':
|
23 |
-
case 'jpeg':
|
24 |
-
header('Content-type: image/jpeg');
|
25 |
-
break;
|
26 |
-
case 'png':
|
27 |
-
header('Content-type: image/png');
|
28 |
-
break;
|
29 |
-
}
|
30 |
-
if (@readfile($source) === false) {
|
31 |
-
header('X-WebP-On-Demand-Error: Could not read file');
|
32 |
-
}
|
33 |
-
}
|
34 |
-
|
35 |
-
private static function addWebPOnDemandHeader($text, $options)
|
36 |
-
{
|
37 |
-
if ($options['add-x-webp-on-demand-headers']) {
|
38 |
-
header('X-WebP-On-Demand: ' . $text);
|
39 |
-
}
|
40 |
-
}
|
41 |
-
|
42 |
-
private static function addVaryHeader($options)
|
43 |
-
{
|
44 |
-
if ($options['add-vary-header']) {
|
45 |
-
header('Vary: Accept');
|
46 |
-
}
|
47 |
-
}
|
48 |
-
|
49 |
-
|
50 |
-
public static function serve($source, $destination, $options)
|
51 |
-
{
|
52 |
-
$options = array_merge(self::$defaultOptions, $options);
|
53 |
-
|
54 |
-
if (empty($source)) {
|
55 |
-
self::addWebPOnDemandHeader('Failed (Missing source argument)', $options);
|
56 |
-
}
|
57 |
-
if (empty($destination)) {
|
58 |
-
self::addWebPOnDemandHeader('Failed (Missing destination argument)', $options);
|
59 |
-
}
|
60 |
-
|
61 |
-
if ($options['show-report']) {
|
62 |
-
// Load WebPConvertAndServe (only when needed)
|
63 |
-
if (isset($options['require-for-conversion'])) {
|
64 |
-
require($options['require-for-conversion']);
|
65 |
-
}
|
66 |
-
|
67 |
-
self::addWebPOnDemandHeader('Reporting...', $options);
|
68 |
-
|
69 |
-
\WebPConvertAndServe\WebPConvertAndServe::convertAndReport($source, $destination, $options);
|
70 |
-
return;
|
71 |
-
}
|
72 |
-
|
73 |
-
if ($options['original']) {
|
74 |
-
self::addWebPOnDemandHeader('Serving original image (was explicitly told to)', $options);
|
75 |
-
self::serveOriginal($source);
|
76 |
-
}
|
77 |
-
if (file_exists($destination) && (!$options['reconvert'])) {
|
78 |
-
$timestampSource = filemtime($source);
|
79 |
-
$timestampDestination = filemtime($destination);
|
80 |
-
|
81 |
-
if (($timestampSource === false) &&
|
82 |
-
($timestampDestination !== false) &&
|
83 |
-
($timestampSource > $timestampDestination)) {
|
84 |
-
// It must be reconverted...
|
85 |
-
// will be done in a subsequent block...
|
86 |
-
} else {
|
87 |
-
$filesizeDestination = filesize($destination);
|
88 |
-
$filesizeSource = filesize($source);
|
89 |
-
|
90 |
-
// Serve original image, if the converted image is larger
|
91 |
-
if (($filesizeSource !== false) &&
|
92 |
-
($filesizeDestination !== false) &&
|
93 |
-
($filesizeDestination > $filesizeSource)) {
|
94 |
-
self::addWebPOnDemandHeader(
|
95 |
-
'Serving original image - because it is smaller than the converted!',
|
96 |
-
$options
|
97 |
-
);
|
98 |
-
self::addVaryHeader($options);
|
99 |
-
self::serveOriginal($source);
|
100 |
-
} else {
|
101 |
-
// Serve existing converted image
|
102 |
-
//echo $destination;
|
103 |
-
header('Content-type: image/webp');
|
104 |
-
self::addWebPOnDemandHeader('Serving existing converted image', $options);
|
105 |
-
self::addVaryHeader($options);
|
106 |
-
|
107 |
-
if (@readfile($destination) === false) {
|
108 |
-
header('X-WebP-On-Demand-Error: Could not read file');
|
109 |
-
}
|
110 |
-
}
|
111 |
-
return;
|
112 |
-
}
|
113 |
-
}
|
114 |
-
|
115 |
-
// We are still here... This means we should ignite the converter, possibly doing a reconversion
|
116 |
-
|
117 |
-
// Load WebPConvertAndServe (we only do that when it is needed)
|
118 |
-
if (isset($options['require-for-conversion'])) {
|
119 |
-
require($options['require-for-conversion']);
|
120 |
-
}
|
121 |
-
|
122 |
-
self::addWebPOnDemandHeader('Converting image (handed over to WebPConvertAndServe)', $options);
|
123 |
-
|
124 |
-
// We do not add "Vary Accept" header here, because WebPConvertAndServe will do that (if successful)
|
125 |
-
|
126 |
-
unset($options['show-report']);
|
127 |
-
unset($options['reconvert']);
|
128 |
-
unset($options['original']);
|
129 |
-
unset($options['add-x-webp-on-demand-headers']);
|
130 |
-
unset($options['require-for-conversion']);
|
131 |
-
|
132 |
-
|
133 |
-
\WebPConvertAndServe\WebPConvertAndServe::convertAndServe($source, $destination, $options);
|
134 |
-
}
|
135 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wod/webp-on-demand.php
CHANGED
@@ -1,8 +1,10 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
require 'webp-on-demand.inc';
|
|
|
|
|
4 |
|
5 |
-
use \
|
6 |
|
7 |
$options = [];
|
8 |
|
@@ -15,7 +17,25 @@ fclose($handle);
|
|
15 |
$options = json_decode($json, true);
|
16 |
//print_r($options);
|
17 |
|
18 |
-
$options['require-for-conversion'] = 'webp-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
if ($options['forward-query-string']) {
|
21 |
if (isset($_GET['debug'])) {
|
@@ -47,4 +67,4 @@ if (substr($source, 0, strlen($applicationRoot)) === $applicationRoot) {
|
|
47 |
//echo $source . '<br>';
|
48 |
//echo $destination . '<br>';
|
49 |
//echo $sourceRel;
|
50 |
-
|
1 |
<?php
|
2 |
|
3 |
+
//require 'webp-on-demand-1.inc';
|
4 |
+
require '../vendor/rosell-dk/webp-convert/build/webp-on-demand-1.inc';
|
5 |
+
//require '../vendor/autoload.php';
|
6 |
|
7 |
+
use \WebPConvert\WebPConvert;
|
8 |
|
9 |
$options = [];
|
10 |
|
17 |
$options = json_decode($json, true);
|
18 |
//print_r($options);
|
19 |
|
20 |
+
$options['require-for-conversion'] = 'webp-on-demand-2.inc';
|
21 |
+
|
22 |
+
$gmagickHere = false;
|
23 |
+
foreach ($options['converters'] as &$converter) {
|
24 |
+
if (isset($converter['converter'])) {
|
25 |
+
$converterId = $converter['converter'];
|
26 |
+
} else {
|
27 |
+
$converterId = $converter;
|
28 |
+
}
|
29 |
+
if ($converterId == 'cwebp') {
|
30 |
+
$converter['options']['rel-path-to-precompiled-binaries'] = '../src/Converters/Binaries';
|
31 |
+
}
|
32 |
+
if ($converterId == 'gmagick') {
|
33 |
+
$gmagickHere = true;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
if (!$gmagickHere) {
|
37 |
+
$options['converters'][] = 'gmagick';
|
38 |
+
}
|
39 |
|
40 |
if ($options['forward-query-string']) {
|
41 |
if (isset($_GET['debug'])) {
|
67 |
//echo $source . '<br>';
|
68 |
//echo $destination . '<br>';
|
69 |
//echo $sourceRel;
|
70 |
+
WebPConvert::convertAndServe($source, $destination, $options);
|