Yireo_WebP - Version 1.0.3

Version Notes

No notes

Download this release

Release Info

Developer Yireo
Extension Yireo_WebP
Version 1.0.3
Comparing to
See all releases


Code changes from version 1.0.0 to 1.0.3

app/code/community/Yireo/Webp/Block/Adminhtml/System/Config/Field/Gd.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Yireo Webp for Magento
4
+ *
5
+ * @package Yireo_Webp
6
+ * @author Yireo <info@yireo.com>
7
+ * @copyright 2015 Yireo <https://www.yireo.com/>
8
+ * @license Open Source License (OSL v3)
9
+ */
10
+
11
+ /**
12
+ * Webp helper
13
+ */
14
+ class Yireo_Webp_Block_Adminhtml_System_Config_Field_Gd extends Mage_Adminhtml_Block_System_Config_Form_Field
15
+ {
16
+ /**
17
+ * Override method to output our custom HTML with JavaScript
18
+ *
19
+ * @param Varien_Data_Form_Element_Abstract $element
20
+ * @return String
21
+ */
22
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
23
+ {
24
+ $html = parent::_getElementHtml($element);
25
+
26
+ $html .= $this->getCheckLine('GD support for WebP', $this->doesGdInfoIncludeWebp());
27
+ $html .= $this->getCheckLine('Function <code>imagewebp()</code> available', $this->doesImagewebpFunctionExist());
28
+
29
+ return $html;
30
+ }
31
+
32
+ /**
33
+ * @param $label
34
+ * @param $value
35
+ *
36
+ * @return string
37
+ */
38
+ protected function getCheckLine($label, $value)
39
+ {
40
+ return '<p class="note">' . $label . ' = ' . $this->getCheckLabel($value) . '</p>';
41
+ }
42
+
43
+ /**
44
+ * @param $value
45
+ *
46
+ * @return string
47
+ */
48
+ protected function getCheckLabel($value)
49
+ {
50
+ if ($value == true) {
51
+ return $this->__('Yes');
52
+ }
53
+
54
+ return $this->__('No');
55
+ }
56
+
57
+ /**
58
+ * @return bool
59
+ */
60
+ protected function doesImagewebpFunctionExist()
61
+ {
62
+ if (function_exists('imagewebp')) {
63
+ return true;
64
+ }
65
+
66
+ return false;
67
+ }
68
+
69
+ /**
70
+ * @return bool
71
+ */
72
+ protected function doesGdInfoIncludeWebp()
73
+ {
74
+ if (function_exists('gd_info') == false) {
75
+ return false;
76
+ }
77
+
78
+ $gdInfo = gd_info();
79
+ foreach ($gdInfo as $gdLabel => $gdValue) {
80
+ if (stristr($gdLabel, 'webp')) {
81
+ return (bool) $gdValue;
82
+ }
83
+ }
84
+
85
+ return false;
86
+ }
87
+ }
app/code/community/Yireo/Webp/Helper/Data.php CHANGED
@@ -1,10 +1,10 @@
1
  <?php
2
  /**
3
- * Yireo Webp for Magento
4
  *
5
  * @package Yireo_Webp
6
- * @author Yireo (http://www.yireo.com/)
7
- * @copyright Copyright 2015 Yireo (http://www.yireo.com/)
8
  * @license Open Source License (OSL v3)
9
  */
10
 
@@ -13,140 +13,355 @@
13
  */
14
  class Yireo_Webp_Helper_Data extends Mage_Core_Helper_Abstract
15
  {
16
- /*
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  * Method to check whether this extension is enabled
 
 
18
  */
19
  public function enabled()
20
  {
21
- $config_enabled = (bool)Mage::getStoreConfig('web/webp/enabled');
22
- if($config_enabled == false) {
23
  return false;
24
  }
25
 
26
- if(isset($_COOKIE['webp']) && $_COOKIE['webp'] == 1) {
27
  return true;
28
  }
29
 
30
- $browser = (isset($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : null;
31
- if(preg_match('/Chrome\/(9|10|11|12|13|14|15|16)/', $browser)) {
32
  return true;
33
  }
34
 
35
  // Check for GD support
36
- if (function_exists('imagewebp')) {
37
  return true;
38
  }
39
 
40
  // Check for potential cwebp execution
41
- $cwebp = Mage::getStoreConfig('web/webp/cwebp_path');
42
- if(!empty($cwebp) && function_exists('exec')) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  return true;
44
  }
45
 
46
  return false;
47
  }
48
 
49
- /*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  * Method to check whether WebP should actually be introduced
 
 
 
 
51
  */
52
  public function allowWebp($image)
53
  {
54
  $enabled = $this->enabled();
55
- if($enabled == false) {
56
  return false;
57
  }
58
 
59
- if(empty($image)) {
60
  return false;
61
  }
62
 
63
- if(preg_match('/\.webp$/i', $image)) {
 
64
  return false;
65
  }
66
 
67
- if(!is_writable(dirname($image))) {
68
  return false;
69
  }
70
 
71
  return false;
72
  }
73
 
74
- /*
75
  * Method to convert an image to WebP
 
 
 
 
76
  */
77
  public function convertToWebp($imagePath)
78
  {
79
- if(empty($imagePath) || !file_exists($imagePath) || !is_readable($imagePath)) {
80
- return;
81
  }
82
 
83
- if($this->enabled() == false) {
84
- return;
 
 
 
 
85
  }
86
 
87
  // Detect alpha-transparency in PNG-images and skip it
88
- if(preg_match('/\.png$/', $imagePath)) {
89
- $imageContents = @file_get_contents($image);
90
- $colorType = ord(@file_get_contents($image, NULL, NULL, 25, 1));
91
- if($colorType == 6 || $colorType == 4) {
92
- return;
93
- } elseif(stripos($imageContents, 'PLTE') !== false && stripos($imageContents, 'tRNS') !== false) {
94
- return;
95
- }
96
  }
97
 
98
  // Construct the new WebP image-name
99
- $webpPath = preg_replace('/\.(png|jpg|jpeg)$/i', '.webp', $imagePath);
100
 
101
  // Check for the current WebP image
102
- if(file_exists($webpPath) && filemtime($imagePath) < filemtime($webpPath)) {
103
  return $webpPath;
104
  }
105
 
106
  // GD function
107
- if (function_exists('imagewebp')) {
108
- if(preg_match('/\.png$/', $imagePath) && function_exists('imagecreatefrompng')) {
109
- $image = imagecreatefrompng($imagePath);
110
- } elseif(preg_match('/\.gif$/', $imagePath) && function_exists('imagecreatefromgif')) {
111
- $image = imagecreatefromgif($imagePath);
112
- } elseif(preg_match('/\.(jpg|jpeg)$/', $imagePath) && function_exists('imagecreatefromjpeg')) {
113
- $image = imagecreatefromjpeg($imagePath);
114
- } else {
115
- return;
116
- }
117
-
118
- imagewebp($image, $webpPath);
119
  return $webpPath;
120
  }
121
 
122
  // Only do the following if the WebP image does not yet exist, or if the original PNG/JPEG seems to be updated
123
- if((!file_exists($webpPath)) || (file_exists($imagePath) && filemtime($imagePath) > filemtime($webpPath))) {
124
- $cwebp = Mage::getStoreConfig('web/webp/cwebp_path');
125
- $cmd = $cwebp.' -quiet '.$imagePath.' -o '.$webpPath;
126
- exec($cmd, $output, $return);
127
- return $webpPath;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  }
129
 
130
- return;
 
 
 
 
131
  }
132
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  public function getSystemPaths()
134
  {
135
  $systemPaths = array(
136
  'skin' => array(
137
  'url' => Mage::getBaseUrl('skin'),
138
- 'path' => Mage::getBaseDir('skin'),
139
- ),
140
  'media' => array(
141
  'url' => Mage::getBaseUrl('media'),
142
- 'path' => Mage::getBaseDir('media'),
143
- ),
144
  'base' => array(
145
  'url' => Mage::getBaseUrl(),
146
- 'path' => Mage::getBaseDir('base'),
147
- ),
148
- );
149
 
150
  return $systemPaths;
151
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  }
1
  <?php
2
  /**
3
+ * Yireo Webp for Magento
4
  *
5
  * @package Yireo_Webp
6
+ * @author Yireo <info@yireo.com>
7
+ * @copyright 2015 Yireo <https://www.yireo.com/>
8
  * @license Open Source License (OSL v3)
9
  */
10
 
13
  */
14
  class Yireo_Webp_Helper_Data extends Mage_Core_Helper_Abstract
15
  {
16
+ /**
17
+ * @var Yireo_Webp_Helper_File
18
+ */
19
+ protected $fileHelper;
20
+
21
+ /**
22
+ * Constructor
23
+ */
24
+ public function __construct()
25
+ {
26
+ $this->fileHelper = Mage::helper('webp/file');
27
+ }
28
+
29
+ /**
30
  * Method to check whether this extension is enabled
31
+ *
32
+ * @return bool
33
  */
34
  public function enabled()
35
  {
36
+ if ($this->isModuleEnabled() == false) {
 
37
  return false;
38
  }
39
 
40
+ if ($this->hasWebpCookieEnabled()) {
41
  return true;
42
  }
43
 
44
+ /** @var Mage_Core_Helper_Http $httpHelper */
45
+ if ($this->isChromeBrowser()) {
46
  return true;
47
  }
48
 
49
  // Check for GD support
50
+ if ($this->hasGdSupport()) {
51
  return true;
52
  }
53
 
54
  // Check for potential cwebp execution
55
+ if ($this->hasBinarySupport()) {
56
+ return true;
57
+ }
58
+
59
+ return false;
60
+ }
61
+
62
+ /**
63
+ * @return bool
64
+ */
65
+ protected function hasWebpCookieEnabled()
66
+ {
67
+ $webpCookie = (int)Mage::app()
68
+ ->getRequest()
69
+ ->getCookie('webp', 0);
70
+
71
+ if ($webpCookie == 1) {
72
+ return true;
73
+ }
74
+
75
+ return false;
76
+ }
77
+
78
+ /**
79
+ * @return bool
80
+ */
81
+ protected function hasBinarySupport()
82
+ {
83
+ if (Mage::getStoreConfig('web/webp/cwebp_enabled') == 0) {
84
+ return false;
85
+ }
86
+
87
+ $cwebp = $this->getCwebpBinary();
88
+ if (empty($cwebp)) {
89
+ return false;
90
+ }
91
+
92
+ if (function_exists('exec') == false) {
93
+ return false;
94
+ }
95
+
96
+ return true;
97
+ }
98
+
99
+ /**
100
+ * @return bool
101
+ */
102
+ protected function hasGdSupport()
103
+ {
104
+ if (Mage::getStoreConfig('web/webp/gd_enabled') == 0) {
105
+ return false;
106
+ }
107
+
108
+ if (!function_exists('imagewebp')) {
109
+ return false;
110
+ }
111
+
112
+ return true;
113
+ }
114
+
115
+ /**
116
+ * @return bool
117
+ */
118
+ protected function isChromeBrowser()
119
+ {
120
+ /** @var Mage_Core_Helper_Http $httpHelper */
121
+ $httpHelper = Mage::helper('core/http');
122
+ $browser = $httpHelper->getHttpUserAgent();
123
+ if (preg_match('/Chrome\/(9|10|11|12|13|14|15|16)/', $browser)) {
124
  return true;
125
  }
126
 
127
  return false;
128
  }
129
 
130
+ /**
131
+ * @return bool
132
+ */
133
+ public function isModuleEnabled()
134
+ {
135
+ if ((bool)Mage::getStoreConfig('advanced/modules_disable_output/Yireo_WebP')) {
136
+ return false;
137
+ }
138
+
139
+ $config_enabled = (bool)Mage::getStoreConfig('web/webp/enabled');
140
+ if ($config_enabled == false) {
141
+ return false;
142
+ }
143
+
144
+ return true;
145
+ }
146
+
147
+ /**
148
  * Method to check whether WebP should actually be introduced
149
+ *
150
+ * @param string $image
151
+ *
152
+ * @return bool
153
  */
154
  public function allowWebp($image)
155
  {
156
  $enabled = $this->enabled();
157
+ if ($enabled == false) {
158
  return false;
159
  }
160
 
161
+ if (empty($image)) {
162
  return false;
163
  }
164
 
165
+ // The image already exists
166
+ if (preg_match('/\.webp$/i', $image)) {
167
  return false;
168
  }
169
 
170
+ if (!$this->fileHelper->isWritableDir($image)) {
171
  return false;
172
  }
173
 
174
  return false;
175
  }
176
 
177
+ /**
178
  * Method to convert an image to WebP
179
+ *
180
+ * @param string $imagePath
181
+ *
182
+ * @return string
183
  */
184
  public function convertToWebp($imagePath)
185
  {
186
+ if (empty($imagePath)) {
187
+ return false;
188
  }
189
 
190
+ if (!$this->fileHelper->exists($imagePath)) {
191
+ return false;
192
+ }
193
+
194
+ if ($this->enabled() == false) {
195
+ return false;
196
  }
197
 
198
  // Detect alpha-transparency in PNG-images and skip it
199
+ if ($this->hasAlphaTransparency($imagePath)) {
200
+ return false;
 
 
 
 
 
 
201
  }
202
 
203
  // Construct the new WebP image-name
204
+ $webpPath = $this->getWebpNameFromImage($imagePath);
205
 
206
  // Check for the current WebP image
207
+ if ($this->fileHelper->exists($webpPath) && $this->fileHelper->isNewerThan($webpPath, $imagePath)) {
208
  return $webpPath;
209
  }
210
 
211
  // GD function
212
+ $webpPath = $this->convertToWebpViaGd($imagePath, $webpPath);
213
+ if ($this->fileHelper->exists($webpPath)) {
 
 
 
 
 
 
 
 
 
 
214
  return $webpPath;
215
  }
216
 
217
  // Only do the following if the WebP image does not yet exist, or if the original PNG/JPEG seems to be updated
218
+ return $this->convertToWebpViaBinary($imagePath, $webpPath);
219
+ }
220
+
221
+ /**
222
+ * Method to convert an image to WebP using the GD method
223
+ *
224
+ * @param $imagePath
225
+ * @param $webpPath
226
+ *
227
+ * @return bool
228
+ */
229
+ public function convertToWebpViaGd($imagePath, $webpPath)
230
+ {
231
+ if ($this->hasGdSupport() == false) {
232
+ return false;
233
+ }
234
+
235
+ if (preg_match('/\.png$/', $imagePath) && function_exists('imagecreatefrompng')) {
236
+ $image = imagecreatefrompng($imagePath);
237
+ } elseif (preg_match('/\.gif$/', $imagePath) && function_exists('imagecreatefromgif')) {
238
+ $image = imagecreatefromgif($imagePath);
239
+ } elseif (preg_match('/\.(jpg|jpeg)$/', $imagePath) && function_exists('imagecreatefromjpeg')) {
240
+ $image = imagecreatefromjpeg($imagePath);
241
+ } else {
242
+ return false;
243
+ }
244
+
245
+ imagewebp($image, $webpPath);
246
+
247
+ return $webpPath;
248
+ }
249
+
250
+ /**
251
+ * Method to convert an image to WebP using the binary method
252
+ *
253
+ * @param $imagePath
254
+ * @param $webpPath
255
+ *
256
+ * @return bool
257
+ */
258
+ public function convertToWebpViaBinary($imagePath, $webpPath)
259
+ {
260
+ if ($this->hasBinarySupport() == false) {
261
+ return false;
262
  }
263
 
264
+ $cwebp = $this->getCwebpBinary();
265
+ $cmd = $cwebp . ' -quiet ' . $imagePath . ' -o ' . $webpPath;
266
+ exec($cmd, $output, $return);
267
+
268
+ return $webpPath;
269
  }
270
 
271
+ /**
272
+ * Detect whether an image has PNG alpha transparency
273
+ *
274
+ * @param $image
275
+ *
276
+ * @return bool
277
+ */
278
+ public function hasAlphaTransparency($image)
279
+ {
280
+ if (empty($image)) {
281
+ return false;
282
+ }
283
+
284
+ if ($this->fileHelper->exists($image) == false) {
285
+ return false;
286
+ }
287
+
288
+ if (preg_match('/\.png$/', $image)) {
289
+ return false;
290
+ }
291
+
292
+ $fileIo = new Yireo_Webp_Lib_Io_File();
293
+ $fileIo->setCwd(dirname($image));
294
+ $fileIo->setIwd(dirname($image));
295
+
296
+ $imageContents = $fileIo->read($image);
297
+ $colorType = ord(substr($imageContents, 25, 1));
298
+
299
+ if ($colorType == 6 || $colorType == 4) {
300
+ return true;
301
+ } elseif (stripos($imageContents, 'PLTE') !== false && stripos($imageContents, 'tRNS') !== false) {
302
+ return true;
303
+ }
304
+
305
+ return false;
306
+ }
307
+
308
+ /**
309
+ * Get the WebP path equivalent of an image path
310
+ *
311
+ * @param $image
312
+ *
313
+ * @return mixed
314
+ */
315
+ public function getWebpNameFromImage($image)
316
+ {
317
+ return preg_replace('/\.(png|jpg|jpeg)$/i', '.webp', $image);
318
+ }
319
+
320
+ /**
321
+ * Return all the system paths
322
+ *
323
+ * @return array
324
+ */
325
  public function getSystemPaths()
326
  {
327
  $systemPaths = array(
328
  'skin' => array(
329
  'url' => Mage::getBaseUrl('skin'),
330
+ 'path' => Mage::getBaseDir('skin').DS),
 
331
  'media' => array(
332
  'url' => Mage::getBaseUrl('media'),
333
+ 'path' => Mage::getBaseDir('media').DS),
 
334
  'base' => array(
335
  'url' => Mage::getBaseUrl(),
336
+ 'path' => Mage::getBaseDir('base').DS));
 
 
337
 
338
  return $systemPaths;
339
  }
340
+
341
+ /**
342
+ * Get the path to the "cwebp" binary
343
+ *
344
+ * @return string
345
+ */
346
+ public function getCwebpBinary()
347
+ {
348
+ $cwebp = $this->getCwebpPath();
349
+ if (empty($cwebp)) {
350
+ return null;
351
+ }
352
+
353
+ if (preg_match('/\/$/', $cwebp)) {
354
+ return $cwebp . 'cwebp';
355
+ }
356
+
357
+ return $cwebp;
358
+ }
359
+
360
+ /**
361
+ * @return mixed
362
+ */
363
+ protected function getCwebpPath()
364
+ {
365
+ return Mage::getStoreConfig('web/webp/cwebp_path');
366
+ }
367
  }
app/code/community/Yireo/Webp/Helper/File.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Yireo Webp for Magento
4
+ *
5
+ * @package Yireo_Webp
6
+ * @author Yireo <info@yireo.com>
7
+ * @copyright 2015 Yireo <https://www.yireo.com/>
8
+ * @license Open Source License (OSL v3)
9
+ */
10
+
11
+ /**
12
+ * Webp file helper
13
+ */
14
+ class Yireo_Webp_Helper_File extends Mage_Core_Helper_Abstract
15
+ {
16
+ /**
17
+ * Method to check to see if a file exists or not
18
+ *
19
+ * @param string $file
20
+ * @return bool
21
+ */
22
+ public function exists($file)
23
+ {
24
+ if (file_exists($file)) {
25
+ return true;
26
+ }
27
+
28
+ $validator = new Zend_Validate_File_Exists();
29
+
30
+ if ($validator->isValid($file) == true) {
31
+ return true;
32
+ }
33
+
34
+ return false;
35
+ }
36
+
37
+ /**
38
+ * Method to check to see if a file is writable or not
39
+ *
40
+ * @param $file
41
+ *
42
+ * @return bool
43
+ */
44
+ public function isWritable($file)
45
+ {
46
+ $fileIo = new Varien_Io_File;
47
+
48
+ return $fileIo->isWriteable($file);
49
+ }
50
+
51
+ /**
52
+ * Method to check to see if a file is writable or not
53
+ *
54
+ * @param $file
55
+ *
56
+ * @return bool
57
+ */
58
+ public function isWritableDir($file)
59
+ {
60
+ $fileIo = new Varien_Io_File;
61
+ $fileHandler = new Varien_File_Object($file);
62
+
63
+ return $fileIo->isWriteable($fileHandler->getDirName());
64
+ }
65
+
66
+ /**
67
+ * Method to return the modification time of a file
68
+ *
69
+ * @param $file
70
+ *
71
+ * @return int
72
+ */
73
+ public function getModificationTime($file)
74
+ {
75
+ $fileHandler = new Varien_File_Object($file);
76
+
77
+ return $fileHandler->getCTime();
78
+ }
79
+
80
+ /**
81
+ * Method to check if a $file1 is newer than a $file2
82
+ *
83
+ * @param $file1
84
+ * @param $file2
85
+ *
86
+ * @return bool
87
+ */
88
+ public function isNewerThan($file1, $file2)
89
+ {
90
+ $file1ModificationTime = $this->getModificationTime($file1);
91
+ $file2ModificationTime = $this->getModificationTime($file2);
92
+
93
+ if($file1ModificationTime > $file2ModificationTime) {
94
+ return true;
95
+ }
96
+
97
+ return false;
98
+ }
99
+ }
app/code/community/Yireo/Webp/Lib/Io/File.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Yireo Webp for Magento
4
+ *
5
+ * @package Yireo_Webp
6
+ * @author Yireo <info@yireo.com>
7
+ * @copyright 2015 Yireo <https://www.yireo.com/>
8
+ * @license Open Source License (OSL v3)
9
+ */
10
+
11
+ /**
12
+ * Webp helper
13
+ */
14
+ class Yireo_Webp_Lib_Io_File extends Varien_Io_File
15
+ {
16
+ public function setIwd($iwd)
17
+ {
18
+ $this->_iwd = $iwd;
19
+ }
20
+
21
+ public function setCwd($cwd)
22
+ {
23
+ $this->_cwd = $cwd;
24
+ }
25
+ }
app/code/community/Yireo/Webp/Model/Observer.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Webp plugin for Magento
4
  *
5
  * @package Yireo_Webp
6
  * @author Yireo (http://www.yireo.com/)
@@ -8,108 +8,219 @@
8
  * @license Open Source License (OSL v3)
9
  */
10
 
 
 
 
11
  class Yireo_Webp_Model_Observer
12
  {
13
- /*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  * Listen to the event core_block_abstract_to_html_after
15
- *
16
- * @access public
17
  * @parameter Varien_Event_Observer $observer
 
18
  * @return $this
19
  */
20
  public function coreBlockAbstractToHtmlAfter($observer)
21
  {
22
- if(Mage::helper('webp')->enabled() == false) {
23
  return $this;
24
  }
25
 
26
  $transport = $observer->getEvent()->getTransport();
27
  $block = $observer->getEvent()->getBlock();
28
- $systemPaths = Mage::helper('webp')->getSystemPaths();
29
 
30
- $allowedBlocks = array('root');
31
- //$allowedBlocks = array('root', 'content');
32
- if(in_array($block->getNameInLayout(), $allowedBlocks)) {
33
- $layout = Mage::app()->getLayout();
34
- $html = $transport->getHtml();
35
-
36
- $newHtml = array();
37
- if(preg_match_all('/\ src=\"([^\"]+)\.(png|jpg|jpeg)/i', $html, $matches)) {
38
-
39
- $imageList = array();
40
- foreach($matches[0] as $index => $match) {
41
-
42
- // Convert the URL to a valid path
43
- $imagePath = null;
44
- $imageUrl = $matches[1][$index].'.'.$matches[2][$index];
45
- if(preg_match('/^http/', $imageUrl)) {
46
- foreach($systemPaths as $systemPath) {
47
- if(strstr($imageUrl, $systemPath['url'])) {
48
- $imagePath = str_replace($systemPath['url'], $systemPath['path'].DS, $imageUrl);
49
- break;
50
- }
51
- }
52
- }
53
-
54
- // If this failed, don't continue
55
- if(!file_exists($imagePath)) {
56
- continue;
57
- }
58
-
59
- // Construct the new WebP image-name
60
- $webpPath = Mage::helper('webp')->convertToWebp($imagePath);
61
-
62
- // If this failed, don't continue
63
- if(empty($webpPath) || file_exists($webpPath) == false) {
64
- continue;
65
- }
66
-
67
- // Convert the path back to a valid URL
68
- $webpUrl = null;
69
- foreach($systemPaths as $systemPath) {
70
- if(strstr($webpPath, $systemPath['path'])) {
71
- $webpUrl = str_replace($systemPath['path'], $systemPath['url'].DS, $webpPath);
72
- break;
73
- }
74
- }
75
-
76
- // Replace the img tag in the HTML
77
- $htmlTag = $matches[0][$index];
78
- $newHtmlTag = str_replace('src="'.$imageUrl, 'data-img="'.md5($imageUrl), $htmlTag);
79
- $html = str_replace($htmlTag, $newHtmlTag, $html);
80
-
81
- // Add the images to the return-array
82
- $imageList[md5($imageUrl)] = array('orig' => $imageUrl, 'webp' => $webpUrl);
83
- }
84
 
85
- // Add a JavaScript-list to the HTML-document
86
- if(!empty($imageList)) {
87
- $newHtml[] = '<script>';
88
- $newHtml[] = 'var SKIN_URL = \''.Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_SKIN).'\';';
89
- $webpCookie = (isset($_COOKIE['webp'])) ? (int)$_COOKIE['webp'] : 0 ;
90
- $newHtml[] = 'var WEBP_COOKIE = '.$webpCookie.';';
91
- $newHtml[] = 'if(webpReplacements == null) { var webpReplacements = new Object(); }';
92
- foreach($imageList as $name => $value) {
93
- $newHtml[] = 'webpReplacements[\''.$name.'\'] = '.json_encode($value);
94
- }
95
- $newHtml[] = '</script>';
96
- }
 
 
 
97
  }
98
 
99
- if($block->getNameInLayout() == 'root') {
100
- $newHtml[] = '<script type="text/javascript" src="'.Mage::getBaseUrl('js').'webp/jquery.detect.js"></script>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  }
 
 
102
 
103
- $newHtml = implode("\n", $newHtml)."\n";
104
- if(strstr($html, '</body>')) {
105
- $html = str_replace('</body>', $newHtml.'</body>', $html);
106
- } else {
107
- $html = $html.$newHtml;
 
 
 
 
 
 
 
 
 
108
  }
 
 
109
 
110
- $transport->setHtml($html);
 
 
 
 
 
 
 
 
 
 
 
 
111
  }
112
 
113
- return $this;
114
  }
115
  }
1
  <?php
2
  /**
3
+ * Webp plugin for Magento
4
  *
5
  * @package Yireo_Webp
6
  * @author Yireo (http://www.yireo.com/)
8
  * @license Open Source License (OSL v3)
9
  */
10
 
11
+ /**
12
+ * Class Yireo_Webp_Model_Observer
13
+ */
14
  class Yireo_Webp_Model_Observer
15
  {
16
+ /**
17
+ * @var Yireo_Webp_Helper_Data
18
+ */
19
+ protected $helper;
20
+
21
+ /**
22
+ * @var Yireo_Webp_Helper_File
23
+ */
24
+ protected $fileHelper;
25
+
26
+ /**
27
+ * Constructor
28
+ */
29
+ public function __construct()
30
+ {
31
+ $this->helper = Mage::helper('webp');
32
+ $this->fileHelper = Mage::helper('webp/file');
33
+ }
34
+
35
+ /**
36
+ * @param Mage_Core_Block_Abstract $block
37
+ *
38
+ * @return bool
39
+ */
40
+ protected function isAllowedBlock($block)
41
+ {
42
+ $allowedBlocks = array('root');
43
+
44
+ if (in_array($block->getNameInLayout(), $allowedBlocks)) {
45
+ return true;
46
+ }
47
+
48
+ return false;
49
+ }
50
+
51
+ /**
52
  * Listen to the event core_block_abstract_to_html_after
53
+ *
 
54
  * @parameter Varien_Event_Observer $observer
55
+ *
56
  * @return $this
57
  */
58
  public function coreBlockAbstractToHtmlAfter($observer)
59
  {
60
+ if ($this->helper->enabled() == false) {
61
  return $this;
62
  }
63
 
64
  $transport = $observer->getEvent()->getTransport();
65
  $block = $observer->getEvent()->getBlock();
 
66
 
67
+ if ($this->isAllowedBlock($block) == false) {
68
+ return $this;
69
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
+ $html = $transport->getHtml();
72
+
73
+ if (preg_match_all('/\ src=\"([^\"]+)\.(png|jpg|jpeg)/i', $html, $matches) == false) {
74
+ return $this;
75
+ }
76
+
77
+ $imageList = array();
78
+ foreach ($matches[0] as $index => $match) {
79
+
80
+ // Convert the URL to a valid path
81
+ $imageUrl = $matches[1][$index] . '.' . $matches[2][$index];
82
+ $webpUrl = $this->convertImageUrlToWebp($imageUrl);
83
+
84
+ if (empty($webpUrl)) {
85
+ return false;
86
  }
87
 
88
+ // Replace the img tag in the HTML
89
+ $htmlTag = $matches[0][$index];
90
+ $newHtmlTag = str_replace('src="' . $imageUrl, 'data-img="' . md5($imageUrl), $htmlTag);
91
+ $html = str_replace($htmlTag, $newHtmlTag, $html);
92
+
93
+ // Add the images to the return-array
94
+ $imageList[md5($imageUrl)] = array('orig' => $imageUrl, 'webp' => $webpUrl);
95
+ }
96
+
97
+ // Add a JavaScript-list to the HTML-document
98
+ if (empty($imageList)) {
99
+ return $this;
100
+ }
101
+
102
+ $newHtml = $this->getScriptHtmlLines($imageList);
103
+
104
+ if ($block->getNameInLayout() == 'root') {
105
+ $newHtml[] = '<script type="text/javascript" src="' . Mage::getBaseUrl('js') . 'webp/jquery.detect.js"></script>';
106
+ }
107
+
108
+ $html = $this->addScriptToBody($html, $newHtml);
109
+ $transport->setHtml($html);
110
+
111
+ return $this;
112
+ }
113
+
114
+ /**
115
+ * @param $imageUrl
116
+ *
117
+ * @return bool|mixed
118
+ */
119
+ protected function convertImageUrlToWebp($imageUrl)
120
+ {
121
+ $imagePath = $this->getImagePathFromUrl($imageUrl);
122
+
123
+ if (empty($imagePath)) {
124
+ return false;
125
+ }
126
+
127
+ if ($this->fileHelper->exists($imagePath) == false) {
128
+ return false;
129
+ }
130
+
131
+ // Construct the new WebP image-name
132
+ $webpPath = $this->helper->convertToWebp($imagePath);
133
+
134
+ if (empty($webpPath)) {
135
+ return false;
136
+ }
137
+
138
+ if ($this->fileHelper->exists($webpPath) == false) {
139
+ return false;
140
+ }
141
+
142
+ // Convert the path back to a valid URL
143
+ $webpUrl = $this->getImageUrlFromPath($webpPath);
144
+
145
+ if (empty($webpUrl)) {
146
+ return false;
147
+ }
148
+
149
+ return $webpUrl;
150
+ }
151
+
152
+ /**
153
+ * @param $imageList
154
+ *
155
+ * @return array
156
+ */
157
+ protected function getScriptHtmlLines($imageList)
158
+ {
159
+ $newHtml = array();
160
+
161
+ $newHtml[] = '<script>';
162
+ $newHtml[] = 'var SKIN_URL = \'' . Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_SKIN) . '\';';
163
+ $webpCookie = (int)Mage::app()->getRequest()->getCookie('webp', 0);
164
+
165
+ $newHtml[] = 'var WEBP_COOKIE = ' . $webpCookie . ';';
166
+ $newHtml[] = 'if(webpReplacements == null) { var webpReplacements = new Object(); }';
167
+ foreach ($imageList as $name => $value) {
168
+ $newHtml[] = 'webpReplacements[\'' . $name . '\'] = ' . json_encode($value);
169
+ }
170
+ $newHtml[] = '</script>';
171
+
172
+ return $newHtml;
173
+ }
174
+
175
+ /**
176
+ * @param string $imagePath
177
+ *
178
+ * @return mixed
179
+ */
180
+ protected function getImageUrlFromPath($imagePath)
181
+ {
182
+ $systemPaths = $this->helper->getSystemPaths();
183
+
184
+ foreach ($systemPaths as $systemPath) {
185
+ if (strstr($imagePath, $systemPath['path'])) {
186
+ return str_replace($systemPath['path'], $systemPath['url'], $imagePath);
187
  }
188
+ }
189
+ }
190
 
191
+ /**
192
+ * @param string $imageUrl
193
+ *
194
+ * @return mixed
195
+ */
196
+ protected function getImagePathFromUrl($imageUrl)
197
+ {
198
+ $systemPaths = $this->helper->getSystemPaths();
199
+
200
+ if (preg_match('/^http/', $imageUrl)) {
201
+ foreach ($systemPaths as $systemPath) {
202
+ if (strstr($imageUrl, $systemPath['url'])) {
203
+ return str_replace($systemPath['url'], $systemPath['path'], $imageUrl);
204
+ }
205
  }
206
+ }
207
+ }
208
 
209
+ /**
210
+ * @param $html
211
+ * @param $scriptLines
212
+ *
213
+ * @return mixed|string
214
+ */
215
+ protected function addScriptToBody($html, $scriptLines)
216
+ {
217
+ $script = implode("\n", $scriptLines) . "\n";
218
+ if (strstr($html, '</body>')) {
219
+ $html = str_replace('</body>', $script . '</body>', $html);
220
+ } else {
221
+ $html = $html . $script;
222
  }
223
 
224
+ return $html;
225
  }
226
  }
app/code/community/Yireo/Webp/etc/config.xml CHANGED
@@ -13,7 +13,7 @@
13
 
14
  <modules>
15
  <Yireo_Webp>
16
- <version>1.0.0</version>
17
  </Yireo_Webp>
18
  </modules>
19
 
@@ -65,7 +65,9 @@
65
  <enabled>1</enabled>
66
  <load_css>0</load_css>
67
  <load_jquery>1</load_jquery>
 
68
  <cwebp_path></cwebp_path>
 
69
  </webp>
70
  </web>
71
  </default>
13
 
14
  <modules>
15
  <Yireo_Webp>
16
+ <version>1.0.3</version>
17
  </Yireo_Webp>
18
  </modules>
19
 
65
  <enabled>1</enabled>
66
  <load_css>0</load_css>
67
  <load_jquery>1</load_jquery>
68
+ <cwebp_enabled>1</cwebp_enabled>
69
  <cwebp_path></cwebp_path>
70
+ <gd_enabled>1</gd_enabled>
71
  </webp>
72
  </web>
73
  </default>
app/code/community/Yireo/Webp/etc/system.xml CHANGED
@@ -30,29 +30,52 @@
30
  <show_in_website>1</show_in_website>
31
  <show_in_store>1</show_in_store>
32
  </enabled>
 
 
 
 
 
 
 
 
 
 
33
  <cwebp_path translate="label">
34
  <label>Path to cwebp</label>
35
- <comment><![CDATA[Path to the "cwebp" binary]]></comment>
36
  <frontend_type>text</frontend_type>
37
- <sort_order>2</sort_order>
38
  <show_in_default>1</show_in_default>
39
  <show_in_website>1</show_in_website>
40
  <show_in_store>1</show_in_store>
41
  </cwebp_path>
 
 
 
 
 
 
 
 
 
 
 
42
  <load_jquery translate="label">
43
  <label>Load jQuery</label>
 
44
  <frontend_type>select</frontend_type>
45
  <source_model>adminhtml/system_config_source_yesno</source_model>
46
- <sort_order>1</sort_order>
47
  <show_in_default>1</show_in_default>
48
  <show_in_website>1</show_in_website>
49
  <show_in_store>1</show_in_store>
50
  </load_jquery>
51
  <load_css translate="label">
52
  <label>Load WebP CSS</label>
 
53
  <frontend_type>select</frontend_type>
54
  <source_model>adminhtml/system_config_source_yesno</source_model>
55
- <sort_order>1</sort_order>
56
  <show_in_default>1</show_in_default>
57
  <show_in_website>1</show_in_website>
58
  <show_in_store>1</show_in_store>
30
  <show_in_website>1</show_in_website>
31
  <show_in_store>1</show_in_store>
32
  </enabled>
33
+ <cwebp_enabled translate="label">
34
+ <label>cwebp Method Enabled</label>
35
+ <comment>Whether you want to use the cwebp binary or not. Make sure to configure your hosting environment properly for this.</comment>
36
+ <frontend_type>select</frontend_type>
37
+ <source_model>adminhtml/system_config_source_yesno</source_model>
38
+ <sort_order>11</sort_order>
39
+ <show_in_default>1</show_in_default>
40
+ <show_in_website>1</show_in_website>
41
+ <show_in_store>1</show_in_store>
42
+ </cwebp_enabled>
43
  <cwebp_path translate="label">
44
  <label>Path to cwebp</label>
45
+ <comment><![CDATA[Example: "/usr/local/bin/cwebp"]]></comment>
46
  <frontend_type>text</frontend_type>
47
+ <sort_order>12</sort_order>
48
  <show_in_default>1</show_in_default>
49
  <show_in_website>1</show_in_website>
50
  <show_in_store>1</show_in_store>
51
  </cwebp_path>
52
+ <gd_enabled translate="label">
53
+ <label>GD Method Enabled</label>
54
+ <comment>Whether you want to use the PHP GD or not</comment>
55
+ <frontend_type>select</frontend_type>
56
+ <frontend_model>webp/adminhtml_system_config_field_gd</frontend_model>
57
+ <source_model>adminhtml/system_config_source_yesno</source_model>
58
+ <sort_order>21</sort_order>
59
+ <show_in_default>1</show_in_default>
60
+ <show_in_website>1</show_in_website>
61
+ <show_in_store>1</show_in_store>
62
+ </gd_enabled>
63
  <load_jquery translate="label">
64
  <label>Load jQuery</label>
65
+ <comment>At this moment jQuery is required for detecting WebP support. Disable this if you are already loading jQuery in another way.</comment>
66
  <frontend_type>select</frontend_type>
67
  <source_model>adminhtml/system_config_source_yesno</source_model>
68
+ <sort_order>31</sort_order>
69
  <show_in_default>1</show_in_default>
70
  <show_in_website>1</show_in_website>
71
  <show_in_store>1</show_in_store>
72
  </load_jquery>
73
  <load_css translate="label">
74
  <label>Load WebP CSS</label>
75
+ <comment>Load a customizable CSS defining WebP-sources for the HTML elements in your theme. This needs to be customized by hand.</comment>
76
  <frontend_type>select</frontend_type>
77
  <source_model>adminhtml/system_config_source_yesno</source_model>
78
+ <sort_order>32</sort_order>
79
  <show_in_default>1</show_in_default>
80
  <show_in_website>1</show_in_website>
81
  <show_in_store>1</show_in_store>
package.xml CHANGED
@@ -1,2 +1,2 @@
1
  <?xml version="1.0"?>
2
- <package><name>Yireo_WebP</name><version>1.0.0</version><stability>stable</stability><license>Open Source License</license><channel>community</channel><extends></extends><summary>No summary</summary><description>No description</description><notes>No notes</notes><authors><author><name>Yireo</name><user>yireo</user><email>info@yireo.com</email></author></authors><date>2015-01-07</date><time>1:38:58</time><compatible></compatible><dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies><contents><target name="mage"><dir name="skin"><dir name="frontend"><dir name="default"><dir name="default"><dir name="css"><file name="webp.css" hash="0edbf3ac7d124afb09332c5c67f68c98"/></dir></dir></dir></dir></dir><dir name="js"><dir name="webp"><file name="jquery.detect.js" hash="d73a6aaf2b64bf23700425b0710b126a"/><file name="jquery.js" hash="4e2a6874f8b028fa23591492284a1643"/></dir></dir><dir name="app"><dir name="etc"><dir name="modules"><file name="Yireo_Webp.xml" hash="ce4be2ddd8bcb72b3e28c138cabe4539"/></dir></dir><dir name="design"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="webp.xml" hash="cc1e3268c9e14c9258afa260c440e25c"/></dir></dir></dir></dir></dir><dir name="code"><dir name="community"><dir name="Yireo"><dir name="Webp"><dir name="etc"><file name="config.xml" hash="b70ef66676f6a82f75d0fccc86704935"/><file name="system.xml" hash="3d9d1794b4bff1af11b251c2921081a1"/></dir><dir name="Model"><file name="Observer.php" hash="86a8b8c4af40a938c784544492f239d1"/></dir><dir name="Helper"><file name="Data.php" hash="fcd9976aa024fa697c1cb0d11115035f"/></dir></dir></dir></dir></dir></dir></target></contents></package>
1
  <?xml version="1.0"?>
2
+ <package><name>Yireo_WebP</name><version>1.0.3</version><stability>stable</stability><license>Open Source License</license><channel>community</channel><extends></extends><summary>No summary</summary><description>No description</description><notes>No notes</notes><authors><author><name>Yireo</name><user>yireo</user><email>info@yireo.com</email></author></authors><date>2016-02-29</date><time>3:42:46</time><compatible></compatible><dependencies><required><php><min>5.4.0</min><max>6.0.0</max></php></required></dependencies><contents><target name="mage"><dir name="skin"><dir name="frontend"><dir name="default"><dir name="default"><dir name="images"><dir name="webp"><file name="test.webp" hash="0e2687e3a6c95084e6ce912aa45d3803"/></dir></dir><dir name="css"><file name="webp.css" hash="0edbf3ac7d124afb09332c5c67f68c98"/></dir></dir></dir></dir></dir><dir name="js"><dir name="webp"><file name="jquery.detect.js" hash="aeb31fc9a097c84db6fb9009c832ccfe"/><file name="jquery.js" hash="4e2a6874f8b028fa23591492284a1643"/></dir></dir><dir name="app"><dir name="etc"><dir name="modules"><file name="Yireo_Webp.xml" hash="ce4be2ddd8bcb72b3e28c138cabe4539"/></dir></dir><dir name="design"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="webp.xml" hash="cc1e3268c9e14c9258afa260c440e25c"/></dir></dir></dir></dir></dir><dir name="code"><dir name="community"><dir name="Yireo"><dir name="Webp"><dir name="etc"><file name="config.xml" hash="574b7f015e32b381cb7ee43cd42ac504"/><file name="system.xml" hash="9c758689114a6aa64a63f9900686daef"/></dir><dir name="Model"><file name="Observer.php" hash="043a29320c3ff099dc3373851187f34c"/></dir><dir name="Lib"><dir name="Io"><file name="File.php" hash="d0d7e1ab1c7631854222a1600f63ac72"/></dir></dir><dir name="Helper"><file name="Data.php" hash="178785cce9bf6e6575051552269de5ea"/><file name="File.php" hash="f383de5eabc3ffc29504260a5dc06d2c"/></dir><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Field"><file name="Gd.php" hash="bf9bed9b14c1a169db79dcd7555fec09"/></dir></dir></dir></dir></dir></dir></dir></dir></dir></dir></target></contents></package>