├── .gitignore
├── LICENCE.md
├── Plugin.php
├── README.md
├── assets
└── default-not-found.jpg
├── classes
└── Image.php
├── composer.json
├── lang
├── de
│ └── lang.php
├── en
│ └── lang.php
├── fr
│ └── lang.php
├── hu
│ └── lang.php
└── zh-cn
│ └── lang.php
├── models
├── Settings.php
└── settings
│ ├── _tinypng_hint.htm
│ ├── _tinypng_stats.htm
│ └── fields.yaml
└── updates
└── version.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | composer.lock
3 | .DS_Store
--------------------------------------------------------------------------------
/LICENCE.md:
--------------------------------------------------------------------------------
1 | # MIT license
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Plugin.php:
--------------------------------------------------------------------------------
1 | 'toughdeveloper.imageresizer::lang.plugin.name',
21 | 'description' => 'toughdeveloper.imageresizer::lang.plugin.description',
22 | 'author' => 'Tough Developer',
23 | 'icon' => 'icon-picture-o',
24 | 'homepage' => 'https://github.com/toughdeveloper/oc-imageresizer-plugin'
25 | ];
26 | }
27 |
28 | /**
29 | * Registers any back-end permissions used by this plugin.
30 | *
31 | * @return array
32 | */
33 | public function registerPermissions()
34 | {
35 | return [
36 | 'toughdeveloper.imageresizer.access_settings' => [
37 | 'tab' => 'toughdeveloper.imageresizer::lang.permission.tab',
38 | 'label' => 'toughdeveloper.imageresizer::lang.permission.label'
39 | ]
40 | ];
41 | }
42 |
43 | public function boot(){
44 | Validator::extend('valid_tinypng_key', function($attribute, $value, $parameters) {
45 | try {
46 | \Tinify\setKey($value);
47 | \Tinify\validate();
48 | } catch(\Tinify\Exception $e) {
49 | return false;
50 | }
51 |
52 | return true;
53 | });
54 | }
55 |
56 | public function registerMarkupTags()
57 | {
58 | return [
59 | 'filters' => [
60 | 'resize' => function($file_path, $width = false, $height = false, $options = []) {
61 | $image = new Image($file_path);
62 | return $image->resize($width, $height, $options);
63 | },
64 | 'imageWidth' => function($image) {
65 | if (!$image instanceOf Image) {
66 | $image = new Image($image);
67 | }
68 | return getimagesize($image->getCachedImagePath())[0];
69 | },
70 | 'imageHeight' => function($image) {
71 | if (!$image instanceOf Image) {
72 | $image = new Image($image);
73 | }
74 | return getimagesize($image->getCachedImagePath())[1];
75 | }
76 | ]
77 | ];
78 | }
79 |
80 | public function registerSettings()
81 | {
82 | return [
83 | 'settings' => [
84 | 'label' => 'toughdeveloper.imageresizer::lang.settings.label',
85 | 'icon' => 'icon-picture-o',
86 | 'description' => 'toughdeveloper.imageresizer::lang.settings.description',
87 | 'class' => 'ToughDeveloper\ImageResizer\Models\Settings',
88 | 'order' => 0,
89 | 'permissions' => ['toughdeveloper.imageresizer.access_settings']
90 | ]
91 | ];
92 | }
93 |
94 | public function registerListColumnTypes()
95 | {
96 | return [
97 | 'thumb' => [$this, 'evalThumbListColumn'],
98 | ];
99 | }
100 |
101 | public function evalThumbListColumn($value, $column, $record)
102 | {
103 | $config = $column->config;
104 |
105 | // Get config options with defaults
106 | $width = isset($config['width']) ? $config['width'] : 50;
107 | $height = isset($config['height']) ? $config['height'] : 50;
108 | $options = isset($config['options']) ? $config['options'] : [];
109 |
110 | // attachMany relation?
111 | if (isset($record->attachMany[$column->columnName]))
112 | {
113 | $file = $value->first();
114 | }
115 | // attachOne relation?
116 | else if (isset($record->attachOne[$column->columnName]))
117 | {
118 | $file = $value;
119 | }
120 | // Mediafinder
121 | else
122 | {
123 | $file = storage_path() . '/app/media' . $value;
124 | }
125 |
126 | $image = new Image($file);
127 | return $image->resize($width, $height, $options)->render();
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Image Resizer
2 |
3 | - [Introduction](#introduction)
4 | - [Available filters](#filters)
5 | - [Using a string](#string)
6 | - [Using a variable](#variable)
7 | - [resize()](#resize)
8 | - [imageWidth() - imageHeight()](#imageDimensions)
9 | - [Image Compression](#compression)
10 |
11 |
12 | ## Introduction
13 |
14 | Resizes an image to the required dimensions. It accepts a string with a file path to the image or a `October\Rain\Database\Attach\File` object (you will have one of these if you have used the attachOne or AttachMany relationship)
15 |
16 | Please note, the not found image can be overwritten via the settings in the admin area.
17 |
18 |
19 | ## Available filters
20 | [`resize(int $width [, int $height , array $options])`](#resize), [`imageWidth()`](#imageDimensions), [`imageHeight()`](#imageDimensions)
21 |
22 |
23 | ### Using a string
24 |
25 | Please note, if the filter alters the URL, you must apply resize afterwards
26 |
27 | ```
28 | {{ 'assets/graphics/background.jpg' | theme | resize(500,500) }}
29 | ```
30 |
31 |
32 | ### Using a variable
33 |
34 | ```
35 | {{ property.image | resize(500) }}
36 | ```
37 |
38 |
39 | ## resize(int $width [, int $height , array $options])
40 |
41 | Resize an image according to the given params. If `$width` or `$height` is `0`, that value is calculated using original image ratio
42 |
43 | ### Options
44 | Key | Description | Default | Options
45 | --- | --- | --- | ---
46 | mode | How the image should be fitted to dimensions | auto | exact, portrait, landscape, auto, fit or crop
47 | offset | Offset the resized image | [0,0] | [int, int]
48 | extension | The extension on the image to return | auto | auto, jpg, jpeg, gif, png
49 | quality | The quality of compression _*requires cache clear_ | 95 | 0-100
50 | sharpen | Sharpen the image across a scale of 0 - 100 _*requires cache clear_ | 0 | 0-100
51 | compress | Whether the image should be compressed or not. Only takes effect when TinyPng compression is enabled. | true | true,false
52 |
53 |
54 | ### Usage in template
55 | ```
56 | {{ property.image | resize(500, false, { mode: 'crop', quality: '80', extension: 'png' }) }}
57 | ```
58 |
59 | ### Usage in PHP
60 |
61 | The image resizer can also be used easily in PHP, as follows:
62 |
63 | ```
64 | use ToughDeveloper\ImageResizer\Classes\Image;
65 |
66 | $image = new Image('/path/to/image.jpg');
67 | $image->resize(150, 200, [ 'mode' => 'crop' ]);
68 | ```
69 |
70 | ### Usage in Backend List
71 |
72 | The image resizer can also be used on backend lists with the type of `thumb`, e.g.
73 |
74 | ```
75 | image:
76 | label: Image
77 | type: thumb
78 | ```
79 |
80 | This works with:
81 |
82 | - AttachMany (uses first image) [Docs](https://octobercms.com/docs/backend/forms#widget-fileupload)
83 | - AttachOne [Docs](https://octobercms.com/docs/backend/forms#widget-fileupload)
84 | - Mediafinder [Docs](https://octobercms.com/docs/backend/forms#widget-mediafinder)
85 |
86 | You can also optionally pass width (default 50), height (default 50) and options as follows:
87 |
88 | ```
89 | image:
90 | label: Image
91 | type: thumb
92 | width: 75
93 | height: 100
94 | options:
95 | mode: crop
96 | ```
97 |
98 |
99 | ## imageWidth() - imageHeight()
100 |
101 | Return current image width/height - useful if you need to know the size of an image resized only by one side.
102 | ```
103 | {{ '/path/to/image.jpg' | resize(250) | imageHeight() }}
104 | ```
105 |
106 |
107 | ## Image Compression via TinyPNG
108 |
109 | The plugin integrates with the TinyPNG API to provide image compression. A developer API key is required, to obtain one visit https://tinypng.com/developers. Once obtained, enter it in the Image Resizer Settings area of October CMS backend.
110 |
111 | TinyPNG offer 500 free compression per month, the plugin automatically caches resized images to save credits, an option to not compress certain images is also available.
112 |
113 | If you are focussed on pagespeed, it is recommended to set your image quality at 70-80 to obtain the lowest filesize whilst still retaining high quality images.
--------------------------------------------------------------------------------
/assets/default-not-found.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matt-pawley/oc-imageresizer-plugin/1b978d16df3f409013c118371e97680023345588/assets/default-not-found.jpg
--------------------------------------------------------------------------------
/classes/Image.php:
--------------------------------------------------------------------------------
1 | originalFilePath = $filePath;
43 |
44 | // Settings are needed often, so offset to variable
45 | $this->settings = Settings::instance();
46 |
47 | // Create a new file object
48 | $this->file = new File;
49 |
50 | if ($filePath instanceof File) {
51 | $this->filePath = $filePath->getLocalPath();
52 | $this->file->file_name = $filePath;
53 | return;
54 | }
55 |
56 | $this->file->file_name = $filePath;
57 |
58 | $this->filePath = (file_exists($filePath))
59 | ? $filePath
60 | : $this->parseFileName($filePath);
61 | }
62 |
63 | /**
64 | * Resizes an Image
65 | *
66 | * @param integer $width The target width
67 | * @param integer $height The target height
68 | * @param array $options The options
69 | *
70 | * @return string
71 | */
72 | public function resize($width = false, $height = false, $options = [])
73 | {
74 | // Parse the default settings
75 | $this->options = $this->parseDefaultSettings($options);
76 |
77 | // Not a file? Display the not found image
78 | if (!is_file($this->filePath)) {
79 | return $this->notFoundImage($width, $height);
80 | }
81 |
82 | // Not a supported extension? Return the image
83 | if (!$this->hasSupportedExtension()) {
84 | return $this;
85 | }
86 |
87 | // If extension is auto, set the actual extension
88 | if (strtolower($this->options['extension']) == 'auto') {
89 | $this->options['extension'] = $this->file->getExtension();
90 | }
91 |
92 | // Set a disk name, this enables caching
93 | $this->file->disk_name = $this->cacheKey();
94 |
95 | // Set the thumbfilename to save passing variables to many functions
96 | $this->thumbFilename = $this->getThumbFilename($width, $height);
97 |
98 | // If the image is cached, don't try resized it.
99 | if (! $this->isImageCached()) {
100 | // Set the file to be created from another file
101 | $this->file->fromFile($this->filePath);
102 |
103 | // Resize it
104 | $thumb = $this->file->getThumb($width, $height, $this->options);
105 |
106 | // Not a gif file? Compress with tinyPNG
107 | if ($this->isCompressionEnabled()) {
108 | $this->compressWithTinyPng();
109 | }
110 |
111 | // Touch the cached image with the original mtime to align them
112 | touch($this->getCachedImagePath(), filemtime($this->filePath));
113 |
114 | $this->deleteTempFile();
115 | }
116 |
117 | // Return the URL
118 | return $this;
119 | }
120 |
121 | /**
122 | * Gets the path for the thumbnail
123 | * @return string
124 | */
125 | public function getCachedImagePath($public = false)
126 | {
127 | // Not a support file extension? Just return the original image
128 | if (!$this->hasSupportedExtension()) {
129 | return ($public === true)
130 | ? url(str_replace(base_path() . '/', '', $this->filePath))
131 | : $this->filePath;
132 | }
133 |
134 | $filePath = $this->file->getStorageDirectory() . $this->getPartitionDirectory() . $this->thumbFilename;
135 |
136 | if ($public === true) {
137 | return url('/storage/app/' . $filePath);
138 | }
139 |
140 | return storage_path('app/' . $filePath);
141 | }
142 |
143 | protected function deleteTempFile()
144 | {
145 | $path = storage_path('app/' . $this->file->getStorageDirectory() . $this->getPartitionDirectory() . $this->file->disk_name);
146 | if (file_exists($path)) {
147 | unlink($path);
148 | }
149 | }
150 |
151 | /**
152 | * Parse the file name to get a relative path for the file
153 | * This is mostly required for scenarios where a twig filter, e.g. theme has been applied.
154 | * @return string
155 | */
156 | protected function parseFileName($filePath)
157 | {
158 | $path = urldecode(parse_url($filePath, PHP_URL_PATH));
159 |
160 | // Create array of commonly used folders
161 | // These will be used to try capture the actual file path to an image without the sub-directory path
162 | $folders = [
163 | config('cms.themesPath'),
164 | config('cms.pluginsPath'),
165 | config('cms.storage.uploads.path'),
166 | config('cms.storage.media.path')
167 | ];
168 |
169 | foreach($folders as $folder)
170 | {
171 | if (str_contains($path, $folder))
172 | {
173 | $paths = explode($folder, $path, 2);
174 | return base_path($folder . end($paths));
175 | }
176 | }
177 |
178 | return base_path($path);
179 | }
180 |
181 | /**
182 | * Works out the default settings
183 | * @return string
184 | */
185 | protected function parseDefaultSettings($options = [])
186 | {
187 | if (!isset($options['mode']) && $this->settings->default_mode) {
188 | $options['mode'] = $this->settings->default_mode;
189 | }
190 | if (!isset($options['offset']) && is_int($this->settings->default_offset_x) && is_int($this->settings->default_offset_y)) {
191 | $options['offset'] = [$this->settings->default_offset_x, $this->settings->default_offset_y];
192 | }
193 | if (!isset($options['extension']) && $this->settings->default_extension) {
194 | $options['extension'] = $this->settings->default_extension;
195 | }
196 | if (!isset($options['quality']) && is_int($this->settings->default_quality)) {
197 | $options['quality'] = $this->settings->default_quality;
198 | }
199 | if (!isset($options['sharpen']) && is_int($this->settings->default_sharpen)) {
200 | $options['sharpen'] = $this->settings->default_sharpen;
201 | }
202 | if (!isset($options['compress'])) {
203 | $options['compress'] = true;
204 | }
205 |
206 | return $options;
207 | }
208 |
209 | /**
210 | * Creates a unique disk name for an image
211 | * @return string
212 | */
213 | protected function cacheKey()
214 | {
215 | $diskName = $this->originalFilePath;
216 |
217 | // Ensures a unique filepath when tinypng compression is enabled
218 | if ($this->isCompressionEnabled()) {
219 | $diskName .= 'tinypng';
220 | }
221 |
222 | return md5($diskName);
223 | }
224 |
225 | /**
226 | * Serves a not found image
227 | * @return string
228 | */
229 | protected function notFoundImage($width, $height)
230 | {
231 | // Have we got a custom not found image? If so, serve this.
232 | if ($this->settings->not_found_image) {
233 | $imagePath = base_path() . config('cms.storage.media.path') . $this->settings->not_found_image;
234 | }
235 |
236 | // If we do not have an existing custom not found image, use the default from this plugin
237 | if (!isset($imagePath) || !file_exists($imagePath)) {
238 | $imagePath = plugins_path('toughdeveloper/imageresizer/assets/default-not-found.jpg');
239 | }
240 |
241 | // Create a new Image object to resize
242 | $file = new Self($imagePath);
243 |
244 | // Return in the specified dimensions
245 | return $file->resize($width, $height, [
246 | 'mode' => 'crop'
247 | ]);
248 | }
249 |
250 | /**
251 | * Compresses a png image using tinyPNG
252 | * @return string
253 | */
254 | protected function compressWithTinyPng()
255 | {
256 | try {
257 | Tinify::setKey($this->settings->tinypng_developer_key);
258 |
259 | $filePath = $this->getCachedImagePath();
260 | $source = Source::fromFile($filePath);
261 | $source->toFile($filePath);
262 | }
263 | catch (\Exception $e) {
264 | // Log error - may help debug
265 | \Log::error('Tiny PNG compress failed', [
266 | 'message' => $e->getMessage(),
267 | 'code' => $e->getCode()
268 | ]);
269 | }
270 |
271 | }
272 |
273 | /**
274 | * Checks if the requested resize/compressed image is already cached.
275 | * Removes the cached image if the original image has a different mtime.
276 | *
277 | * @return bool
278 | */
279 | protected function isImageCached()
280 | {
281 | // if there is no cached image return false
282 | if (!is_file($cached_img = $this->getCachedImagePath())) {
283 | return false;
284 | }
285 |
286 | // if cached image mtime match, the image is already cached
287 | if (filemtime($this->filePath) === filemtime($cached_img)) {
288 | return true;
289 | }
290 |
291 | // delete older cached file
292 | unlink($cached_img);
293 |
294 | // generate new cache file
295 | return false;
296 | }
297 |
298 | /**
299 | * Checks if image compression is enabled for this image.
300 | * @return bool
301 | */
302 | protected function isCompressionEnabled()
303 | {
304 | return ($this->options['extension'] != 'gif' && $this->settings->enable_tinypng && $this->options['compress']);
305 | }
306 |
307 | /**
308 | * Generates a partition for the file.
309 | * return /ABC/DE1/234 for an name of ABCDE1234.
310 | * @param Attachment $attachment
311 | * @param string $styleName
312 | * @return mixed
313 | */
314 | protected function getPartitionDirectory()
315 | {
316 | return implode('/', array_slice(str_split($this->cacheKey(), 3), 0, 3)) . '/';
317 | }
318 |
319 | /**
320 | * Generates a thumbnail filename.
321 | * @return string
322 | */
323 | protected function getThumbFilename($width, $height)
324 | {
325 | $width = (integer) $width;
326 | $height = (integer) $height;
327 |
328 | return 'thumb__' . $width . '_' . $height . '_' . $this->options['offset'][0] . '_' . $this->options['offset'][1] . '_' . $this->options['mode'] . '.' . $this->options['extension'];
329 | }
330 |
331 | /**
332 | * Checks if it is a resizable file extension
333 | * @return boolean
334 | */
335 | protected function hasSupportedExtension()
336 | {
337 | return in_array($this->file->getExtension(), File::$imageExtensions);
338 | }
339 |
340 | /**
341 | * Render an image tag
342 | * @return string
343 | */
344 | public function render()
345 | {
346 | return '';
347 | }
348 |
349 | /**
350 | * Magic method to return the file path
351 | * @return string
352 | */
353 | public function __toString()
354 | {
355 | return $this->getCachedImagePath(true);
356 | }
357 | }
358 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "toughdeveloper/imageresizer",
3 | "type": "october-plugin",
4 | "description": "October CMS Plugin to resize and compress images.",
5 | "license": "MIT",
6 | "website": "https://octobercms.com/plugin/toughdeveloper-imageresizer",
7 | "require": {
8 | "composer/installers": "~1.0",
9 | "tinify/tinify": "^1.3"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/lang/de/lang.php:
--------------------------------------------------------------------------------
1 | [
5 | 'name' => 'Bildskalierung',
6 | 'description' => 'Stellt Twig-Filter zum Skalieren von Bildern bereit.'
7 | ],
8 | 'settings' => [
9 | 'label' => 'Bildskalierung Einstellungen',
10 | 'description' => 'Einstellungen der Bildskalierung verwalten',
11 | 'tab_default' => 'Vorgaben',
12 | 'tab_advanced' => 'Erweitert',
13 | 'not_found_image_label' => 'Nicht gefunden Bild',
14 | 'not_found_image_comment' => 'Zeigt ein anpassbares Bild an, sollte das Bild nicht existieren.',
15 | 'default_mode_label' => 'Standard Modus',
16 | 'default_mode_comment' => 'Wie soll das Bild skaliert werden.',
17 | 'default_offset_x_label' => 'Standard Abstand X',
18 | 'default_offset_x_comment' => 'Setzt einen horizontalen Abstand.',
19 | 'default_offset_y_label' => 'Standard Abstand Y',
20 | 'default_offset_y_comment' => 'Setzt einen vertikalen Abstand.',
21 | 'default_extension_label' => 'Standard Erweiterung',
22 | 'default_extension_comment' => 'Die Erweiterung des zurückgegebenen Bildes.',
23 | 'default_quality_label' => 'Standard Qualität',
24 | 'default_quality_comment' => 'Die Qualität der Komprimierung (erfordert das Leeren des Chaches).',
25 | 'default_sharpen_label' => 'Standard Schärfung',
26 | 'default_sharpen_comment' => 'Schärft das Bild von 0 - 100 (erfordert das Leeren des Chaches).',
27 | 'tinypng_hint' => 'Um einen Entwickler-Schlüssel für TinyPNG zu bekommen, bitte https://tinypng.com/developers besuchen. Mit Angabe der E-Mail Addresse wird ein Link zum Schlüssel gesendet. Die ersten 500 Bilder pro Monat sind gratis, komprimierte Bilder werden gespeichert um die Anfragen zu reduzieren. Für die meisten Seiten reicht dies aus. Es wird geraten dieses Feature nur so wenig wie möglich und nur Live zu benutzen.',
28 | 'enable_tinypng_label' => 'Komprimiere Bilder mit TinyPNG',
29 | 'enable_tinypng_comment' => 'Fügt die Möglichkeit hinzu Bilder mit der tinypng.com API zu komprimieren und so die Dateigröße zu minimieren',
30 | 'tinypng_developer_key_label' => 'Entwickler Schlüssel',
31 | 'tinypng_developer_key_comment' => 'Siehe oben für eine Anleitung zum Erhalt eines Schlüssels',
32 | 'auto' => 'Auto',
33 | 'mode_exact' => 'Exakt',
34 | 'mode_portrait' => 'Hochformat',
35 | 'mode_landscape' => 'Querformat',
36 | 'mode_crop' => 'Abschneiden',
37 | 'tinypng_invalid_key' => 'Der tinypng Schlüssel konnte nicht validiert werden, bitte überprüfen und erneut probieren.',
38 | 'tinypng_compressed_images' => 'Komprimierte Bilder',
39 | 'tinypng_remaining_compressions' => 'Verbleibende kostenlose Komprimierungen',
40 | 'tinypng_days_until_reset' => 'Tage bis zum Reset'
41 | ],
42 | 'permission' => [
43 | 'tab' => 'Bildskalierung',
44 | 'label' => 'Einstellungen verwalten'
45 | ]
46 | ];
47 |
--------------------------------------------------------------------------------
/lang/en/lang.php:
--------------------------------------------------------------------------------
1 | [
5 | 'name' => 'Image Resizer',
6 | 'description' => 'Provides Twig filter to resize images on the fly.'
7 | ],
8 | 'settings' => [
9 | 'label' => 'Image Resizer Settings',
10 | 'description' => 'Configure Image Resizer Settings',
11 | 'tab_default' => 'Defaults',
12 | 'tab_advanced' => 'Advanced',
13 | 'not_found_image_label' => 'Not Found Image',
14 | 'not_found_image_comment' => 'Displays a customizable image if the image doesn\'t exist.',
15 | 'default_mode_label' => 'Default mode',
16 | 'default_mode_comment' => 'How the image should be fitted to dimensions.',
17 | 'default_offset_x_label' => 'Default offset X',
18 | 'default_offset_x_comment' => 'Offset the resized image horizontally.',
19 | 'default_offset_y_label' => 'Default offset Y',
20 | 'default_offset_y_comment' => 'Offset the resized image vertically.',
21 | 'default_extension_label' => 'Default extension',
22 | 'default_extension_comment' => 'The extension on the image to return.',
23 | 'default_quality_label' => 'Default quality',
24 | 'default_quality_comment' => 'The quality of compression (requires cache clear).',
25 | 'default_sharpen_label' => 'Default sharpen',
26 | 'default_sharpen_comment' => 'Sharpen the image across a scale of 0 - 100 (requires cache clear).',
27 | 'tinypng_hint' => 'To obtain your developer key for TinyPNG, please visit https://tinypng.com/developers. Enter your email address and a link to your developer key will be emailed across to you. The first 500 compressions a month are free, compressed images are cached to reduce the number of requests and for most sites this will suffice. It is recommended to keep the number of requests to a minimum, to only enable this setting on production servers.',
28 | 'enable_tinypng_label' => 'Compress images with TinyPNG',
29 | 'enable_tinypng_comment' => 'Adds the ability to run images through tinypng.com API to reduce filesize',
30 | 'tinypng_developer_key_label' => 'Developer Key',
31 | 'tinypng_developer_key_comment' => 'See above for details of how to obtain this',
32 | 'auto' => 'Auto',
33 | 'mode_exact' => 'Exact',
34 | 'mode_portrait' => 'Portrait',
35 | 'mode_landscape' => 'Landscape',
36 | 'mode_crop' => 'Crop',
37 | 'tinypng_invalid_key' => 'The tinypng key entered could not be validated, please check the key and try again.',
38 | 'tinypng_compressed_images' => 'Compressed Images',
39 | 'tinypng_remaining_compressions' => 'Remaining Free Compressions',
40 | 'tinypng_days_until_reset' => 'Days until reset'
41 | ],
42 | 'permission' => [
43 | 'tab' => 'Image Resizer',
44 | 'label' => 'Manage Settings'
45 | ]
46 | ];
47 |
--------------------------------------------------------------------------------
/lang/fr/lang.php:
--------------------------------------------------------------------------------
1 | [
5 | 'name' => 'Image Resizer',
6 | 'description' => 'Fournit un filtre Twig pour redimensionner les images.'
7 | ],
8 | 'settings' => [
9 | 'label' => 'Paramètres Image Resizer',
10 | 'description' => 'Configurer les paramètres d\'Image Resizer',
11 | 'tab_default' => 'Réglages généraux',
12 | 'tab_advanced' => 'Réglages avancés',
13 | 'not_found_image_label' => 'Image introuvable',
14 | 'not_found_image_comment' => 'Affiche une image personnalisée si l\'image n\'existe pas.',
15 | 'default_mode_label' => 'Mode par défaut',
16 | 'default_mode_comment' => 'Comment l\'image doit être adaptée aux dimensions.',
17 | 'default_offset_x_label' => 'Décalage par défaut X',
18 | 'default_offset_x_comment' => 'Décalez l\'image redimensionnée horizontalement.',
19 | 'default_offset_y_label' => 'Décalage par défaut Y',
20 | 'default_offset_y_comment' => 'Décalez l\'image redimensionnée verticalement',
21 | 'default_extension_label' => 'Extension par défaut',
22 | 'default_extension_comment' => 'L\'extension de l\'image affiché.',
23 | 'default_quality_label' => 'Qualité par défaut',
24 | 'default_quality_comment' => 'La qualité de la compression (nécessite la suppression du cache).',
25 | 'default_sharpen_label' => 'Accentuage par défaut',
26 | 'default_sharpen_comment' => 'Accentuez l\'image sur une échelle de 0 à 100 (nécessite la suppression du cache).',
27 | 'tinypng_hint' => 'Pour obtenir votre clé de développeur pour TinyPNG, consultez la page https://tinypng.com/developers. Entrez votre adresse e-mail et un lien vers votre clé développeur vous sera envoyé par courriel. Les 500 premières compressions par mois sont gratuites, les images compressées sont mises en cache afin de réduire le nombre de demandes. Cela suffira pour la plupart des sites. Il est recommandé de limiter le nombre de demandes au minimum afin d\'activer ce paramètre uniquement sur les serveurs de production.',
28 | 'enable_tinypng_label' => 'Compresser les images avec TinyPNG',
29 | 'enable_tinypng_comment' => 'Ajoute la possibilité de compresser des images via l\'API tinypng.com afin de réduire la taille du fichier.',
30 | 'tinypng_developer_key_label' => 'Clé de développeur',
31 | 'tinypng_developer_key_comment' => 'Voir ci-dessus pour savoir comment obtenir la clé.',
32 | 'auto' => 'Auto',
33 | 'mode_exact' => 'Exact',
34 | 'mode_portrait' => 'Portrait',
35 | 'mode_landscape' => 'Paysage',
36 | 'mode_crop' => 'Rogner',
37 | 'tinypng_invalid_key' => 'La clé TinyPNG saisie n\'a pas pu être validée. Veuillez vérifier la clé et réessayer.',
38 | 'tinypng_compressed_images' => 'Images compressées',
39 | 'tinypng_remaining_compressions' => 'Compressions gratuites restantes',
40 | 'tinypng_days_until_reset' => 'Jours jusqu\'à la réinitialisation'
41 | ],
42 | 'permission' => [
43 | 'tab' => 'Image Resizer',
44 | 'label' => 'Gérer les paramètres'
45 | ]
46 | ];
47 |
--------------------------------------------------------------------------------
/lang/hu/lang.php:
--------------------------------------------------------------------------------
1 | [
5 | 'name' => 'Képméretezés',
6 | 'description' => 'Képek dinamikus átméretezése és módosítása.'
7 | ],
8 | 'settings' => [
9 | 'label' => 'Képméretezés',
10 | 'description' => 'Szolgáltatáshoz tartozó beállítások',
11 | 'tab_default' => 'Általános',
12 | 'tab_advanced' => 'Kiegészítők',
13 | 'not_found_image_label' => 'Helyettesítő kép',
14 | 'not_found_image_comment' => 'Ha nem létezik az adott kép, akkor ez a kép jelenik meg.',
15 | 'default_mode_label' => 'Alapértelmezett mód',
16 | 'default_mode_comment' => 'A kép arányának meghatározása.',
17 | 'default_offset_x_label' => 'Alapértelmezett X eltolás',
18 | 'default_offset_x_comment' => 'A kép vízszintes eltolásának mértéke képpontban.',
19 | 'default_offset_y_label' => 'Alapértelmezett Y eltolás',
20 | 'default_offset_y_comment' => 'A kép függőleges eltolásának mértéke képpontban.',
21 | 'default_extension_label' => 'Alapértelmezett kiterjesztés',
22 | 'default_extension_comment' => 'A kép kiterjesztésének fajtája.',
23 | 'default_quality_label' => 'Alapértelmezett minőség',
24 | 'default_quality_comment' => 'A kép minőségének mértéke. 0 és 100 közötti érték lehet.',
25 | 'default_sharpen_label' => 'Alapértelmezett élesítés',
26 | 'default_sharpen_comment' => 'A kép élesítésének mértéke. 0 és 100 közötti érték lehet.',
27 | 'tinypng_hint' => 'A TinyPNG használatához először regisztráljon a https://tinypng.com/developers címen. Ezt követően e-mailben fog kapni egy linket, amin keresztül elérheti a személyes fejlesztői kulcsát. Az első 500 tömörítés ingyenes minden hónapban. Javasoljuk, hogy a havi keret túllépésének elkerülése érdekében, csak éles weboldalnál kapcsolja be a szolgáltatást.',
28 | 'enable_tinypng_label' => 'Képek tömörítése a TinyPNG segítségével',
29 | 'enable_tinypng_comment' => 'A png kiterjesztésű képek méretének csökkentése a szolgáltatással használatával.',
30 | 'tinypng_developer_key_label' => 'Fejlesztői kulcs',
31 | 'tinypng_developer_key_comment' => 'A részleteket a fenti leírásban találja.',
32 | 'auto' => 'Automatikus',
33 | 'mode_exact' => 'Pontos',
34 | 'mode_portrait' => 'Álló',
35 | 'mode_landscape' => 'Fekvő',
36 | 'mode_crop' => 'Levágott',
37 | 'tinypng_invalid_key' => 'A megadott tinypng kulcsot nem lehet érvényesíteni. Kérjük ellenőrizze és próbálja újra.',
38 | 'tinypng_compressed_images' => 'Tömörített képek',
39 | 'tinypng_remaining_compressions' => 'Fennmaradó kompresszió',
40 | 'tinypng_days_until_reset' => 'Napok törlésig'
41 | ],
42 | 'permission' => [
43 | 'tab' => 'Képméretezés',
44 | 'label' => 'Beállítások kezelése'
45 | ]
46 | ];
47 |
--------------------------------------------------------------------------------
/lang/zh-cn/lang.php:
--------------------------------------------------------------------------------
1 | [
5 | 'name' => 'Image Resizer',
6 | 'description' => '提供图片大小条这个的 Twig filter。'
7 | ],
8 | 'settings' => [
9 | 'label' => 'Image Resizer 设置',
10 | 'description' => '配置图片大小调节设置',
11 | 'tab_default' => '默认',
12 | 'tab_advanced' => '高级',
13 | 'not_found_image_label' => '未找到图片',
14 | 'not_found_image_comment' => '在图片不存在时展示一个自定义的图片。',
15 | 'default_mode_label' => '默认模式',
16 | 'default_mode_comment' => '图像应该如何与尺寸匹配。',
17 | 'default_offset_x_label' => '默认 X 轴偏移量',
18 | 'default_offset_x_comment' => '调整大小时垂直方向上的偏移量。',
19 | 'default_offset_y_label' => '默认 Y 轴偏移量',
20 | 'default_offset_y_comment' => '调整大小时垂直方向上的偏移量。',
21 | 'default_extension_label' => '默认扩展名',
22 | 'default_extension_comment' => '返回的图片的扩展名。',
23 | 'default_quality_label' => '默认质量',
24 | 'default_quality_comment' => '图片压缩质量(需要清空缓存)。',
25 | 'default_sharpen_label' => '默认锐化程度',
26 | 'default_sharpen_comment' => '在 0 - 100 范围内锐化图片(需要清空缓存)。',
27 | 'tinypng_hint' => '要申请自己的 TinyPNG 开发者 key, 请访问 https://tinypng.com/developers。输入你的邮箱地址,一个你开发者 key 的链接将会通过邮件发送给你。每个月的前 500 次压缩免费,压缩后的图片会缓存下来,用以减少请求次数,这对于大部分网站已经足够了。建议尽量减少请求数量,仅在生产服务器上启用此设置。',
28 | 'enable_tinypng_label' => '使用 TinyPNG 压缩图片',
29 | 'enable_tinypng_comment' => '提供通过 tinypng.com API 来减少文件体积的能力',
30 | 'tinypng_developer_key_label' => '开发者 Key',
31 | 'tinypng_developer_key_comment' => '要了解如何生成此 Key,请查看上面的提示',
32 | 'auto' => 'Auto',
33 | 'mode_exact' => 'Exact',
34 | 'mode_portrait' => 'Portrait',
35 | 'mode_landscape' => 'Landscape',
36 | 'mode_crop' => 'Crop',
37 | 'tinypng_invalid_key' => '输入的 tinypng 密钥无法验证,请检查密钥并重试',
38 | 'tinypng_compressed_images' => 'Compressed Images',
39 | 'tinypng_remaining_compressions' => 'Remaining Free Compressions',
40 | 'tinypng_days_until_reset' => 'Days until reset'
41 | ],
42 | 'permission' => [
43 | 'tab' => 'Image Resizer',
44 | 'label' => '管理设置'
45 | ]
46 | ];
47 |
--------------------------------------------------------------------------------
/models/Settings.php:
--------------------------------------------------------------------------------
1 | 'integer',
21 | 'default_offset_y' => 'integer',
22 | 'default_quality' => 'integer',
23 | 'default_sharpen' => 'integer'
24 | ];
25 |
26 | public $rules = [
27 | 'default_quality' => 'integer|between:0,100',
28 | 'default_sharpen' => 'integer|between:0,100',
29 | 'tinypng_developer_key' => 'required_if:enable_tinypng,1'
30 | ];
31 |
32 | public $customMessages = [];
33 |
34 | public function __construct(){
35 | $this->customMessages['valid_tinypng_key'] = Lang::get('toughdeveloper.imageresizer::lang.settings.tinypng_invalid_key');
36 |
37 | parent::__construct();
38 | }
39 |
40 | public function beforeValidate()
41 | {
42 | if ($this->enable_tinypng == 1) {
43 | $this->rules['tinypng_developer_key'] .= '|valid_tinypng_key';
44 | }
45 | }
46 |
47 | // Default setting data
48 | public function initSettingsData()
49 | {
50 | $this->default_extension = 'auto';
51 | $this->default_mode = 'auto';
52 | $this->default_offset_x = 0;
53 | $this->default_offset_y = 0;
54 | $this->default_quality = 95;
55 | $this->default_sharpen = 0;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/models/settings/_tinypng_hint.htm:
--------------------------------------------------------------------------------
1 |
= \Lang::get('toughdeveloper.imageresizer::lang.settings.tinypng_hint') ?>
-------------------------------------------------------------------------------- /models/settings/_tinypng_stats.htm: -------------------------------------------------------------------------------- 1 | formWidget->data->tinypng_developer_key; 4 | 5 | if ($key) { 6 | try { 7 | \Tinify\setKey($key); 8 | \Tinify\validate(); 9 | 10 | $validKey = true; 11 | 12 | $compressionsThisMonth = (int) \Tinify\compressionCount(); 13 | $remainingFree = max(0, 500 - $compressionsThisMonth); 14 | } catch(\Tinify\Exception $e) { 15 | 16 | } 17 | } 18 | 19 | $currentDate = new DateTime(date('Y-m-d')); 20 | $currentDate->add(new DateInterval('P1M')); 21 | $firstDayOfNextMonth = $currentDate->format('Y-m-1'); 22 | $firstDayOfNextMonth = new DateTime($firstDayOfNextMonth); 23 | 24 | $now = new DateTime(); 25 | $interval = $now->diff($firstDayOfNextMonth); 26 | $daysUntilRenew = $interval->format('%a'); 27 | 28 | 29 | if ($validKey) 30 | { 31 | ?> 32 |=$daysUntilRenew?>
43 |