Image Optimizer [NAT] Image_Optimizer_nat img_opti_nat_v1 1.2.0 NAT mailto:info@nat.od.ua user->hasPermission('access', 'catalog/product')) {]]> load->model('setting/setting'); if ($this->config->get('module_img_opti_status')) { $nat_pos = $this->config->get('module_img_opti_menu_position'); if ($nat_pos == 'sidebar' || $nat_pos == 'both') { if ($this->user->hasPermission('access', 'extension/module/img_opti')) { $nat_item = array( 'name' => 'Image Optimizer', 'href' => $this->url->link('extension/module/img_opti', 'user_token=' . $this->session->data['user_token'], true), 'children' => array() ); $nat_menu_index = -1; if (isset($data['menus'])) { foreach ($data['menus'] as $k => $menu) { if (isset($menu['id']) && $menu['id'] == 'menu-nat') { $nat_menu_index = $k; break; } } } $exists = false; if ($nat_menu_index > -1 && isset($data['menus'][$nat_menu_index]['children'])) { foreach ($data['menus'][$nat_menu_index]['children'] as $child) { if (isset($child['href']) && strpos($child['href'], 'route=extension/module/img_opti') !== false) { $exists = true; break; } } } if (!$exists) { if ($nat_menu_index > -1) { $data['menus'][$nat_menu_index]['children'][] = $nat_item; } else { $data['menus'][] = array( 'id' => 'menu-nat', 'icon' => 'fa-rocket fw', 'name' => '[NAT] Modules', 'href' => '', 'children' => array($nat_item) ); } } } } } ]]> url->link('common/logout']]> load->model('setting/setting'); if ($this->config->get('module_img_opti_status')) { $nat_pos = $this->config->get('module_img_opti_menu_position'); if ($nat_pos == 'header' || $nat_pos == 'both') { if ($this->user->hasPermission('access', 'extension/module/img_opti')) { $exists = false; foreach ($data['nat_menus'] as $m) { if (isset($m['href']) && strpos($m['href'], 'route=extension/module/img_opti') !== false) { $exists = true; break; } } if (!$exists) { $data['nat_menus'][] = array( 'name' => 'Image Optimizer', 'href' => $this->url->link('extension/module/img_opti', 'user_token=' . $this->session->data['user_token'], true) ); } } } } ]]> ]]> a.img-thumbnail img, a.thumbnail img { width: 100px !important; height: 100px !important; object-fit: contain !important; } ]]> {% endif %} ]]> config->get('module_img_opti_support_svg') && !in_array('svg', $allowed)) { $allowed[] = 'svg'; } if ($this->config->get('module_img_opti_support_webp') && !in_array('webp', $allowed)) { $allowed[] = 'webp'; } ]]> config->get('module_img_opti_support_svg') && !in_array('image/svg+xml', $allowed)) { $allowed[] = 'image/svg+xml'; } if ($this->config->get('module_img_opti_support_webp')) { if (!in_array('image/webp', $allowed)) { $allowed[] = 'image/webp'; } if (!in_array('image/vnd.webp', $allowed)) { $allowed[] = 'image/vnd.webp'; } if (!in_array('image/x-webp', $allowed)) { $allowed[] = 'image/x-webp'; } $uploaded_ext = utf8_strtolower(utf8_substr(strrchr($filename, '.'), 1)); if ($uploaded_ext === 'webp' && !in_array($file['type'], $allowed)) { $allowed[] = $file['type']; } } ]]> ]*>(.*?)<\/script>/is', '', $svg_content); $svg_content = preg_replace('/on\w+\s*=\s*["\'][^"\']*["\']/i', '', $svg_content); $svg_content = preg_replace('/href\s*=\s*["\']\s*javascript:[^"\']*["\']/i', '', $svg_content); @file_put_contents($file['tmp_name'], $svg_content); } } ]]> config->get('module_img_opti_support_svg')) { $ext_list[] = 'svg'; $ext_list[] = 'SVG'; } if ($this->config->get('module_img_opti_support_webp')) { $ext_list[] = 'webp'; $ext_list[] = 'WEBP'; } $files = glob($directory . '/' . $filter_name . '*.{' . implode(',', $ext_list) . '}', GLOB_BRACE); ]]> registry; if ($this->config->get('module_img_opti_status') && $this->config->get('module_img_opti_auto_fake_jpg_guard') && !empty($filename)) { $this->load->model('extension/module/img_opti'); try { $filename = $this->model_extension_module_img_opti->checkAndFixFakeJpgOnTheFly($filename); } catch (\Exception $e) {} } if (empty($filename) || ($filename !== 'no_image.png' && $filename !== 'placeholder.png' && !is_file(DIR_IMAGE . $filename))) { if ($this->config->get('module_img_opti_status') && $this->config->get('module_img_opti_broken_fallback')) { $fallback_image = $this->config->get('module_img_opti_fallback_image'); if ($fallback_image && is_file(DIR_IMAGE . $fallback_image)) { $filename = $fallback_image; } } } if (!empty($filename) && strpos($filename, '.') !== false) { $nat_ext = strtolower(substr(strrchr($filename, '.'), 1)); if ($nat_ext === 'svg' || ($nat_ext === 'webp' && !function_exists('imagewebp'))) { if (isset($this->request->server['HTTPS']) && (($this->request->server['HTTPS'] == 'on' || ($this->request->server['HTTPS'] == '1')))) { return $this->config->get('config_ssl') . 'image/' . str_replace('\\', '/', $filename); } else { return $this->config->get('config_url') . 'image/' . str_replace('\\', '/', $filename); } } } ]]> save(DIR_IMAGE . $image_new);]]> config->get('module_img_opti_status') && $this->config->get('module_img_opti_wm_status')) { $this->load->model('extension/module/img_opti'); try { $this->model_extension_module_img_opti->applyDynamicWatermark(DIR_IMAGE . $image_new, $filename); } catch (\Exception $e) {} } ]]> config->get('module_img_opti_status') && $this->config->get('module_img_opti_wm_status')) { $this->load->model('extension/module/img_opti'); try { $this->model_extension_module_img_opti->applyDynamicWatermark(DIR_IMAGE . $image_new, $filename); } catch (\Exception $e) {} } }]]> registry; if ($this->config->get('module_img_opti_status') && $this->config->get('module_img_opti_auto_fake_jpg_guard') && !empty($filename)) { $this->load->model('extension/module/img_opti'); try { $filename = $this->model_extension_module_img_opti->checkAndFixFakeJpgOnTheFly($filename); } catch (\Exception $e) {} } if (empty($filename) || ($filename !== 'no_image.png' && $filename !== 'placeholder.png' && !is_file(DIR_IMAGE . $filename))) { if ($this->config->get('module_img_opti_status') && $this->config->get('module_img_opti_broken_fallback')) { $fallback_image = $this->config->get('module_img_opti_fallback_image'); if ($fallback_image && is_file(DIR_IMAGE . $fallback_image)) { $filename = $fallback_image; } } } if (!empty($filename) && strpos($filename, '.') !== false) { $nat_ext = strtolower(substr(strrchr($filename, '.'), 1)); if ($nat_ext === 'svg' || ($nat_ext === 'webp' && !function_exists('imagewebp'))) { $nat_https = isset($this->request->server['HTTPS']) && ($this->request->server['HTTPS'] == 'on' || $this->request->server['HTTPS'] == '1'); $nat_base = $nat_https ? (defined('HTTPS_CATALOG') ? HTTPS_CATALOG : $this->config->get('config_ssl')) : (defined('HTTP_CATALOG') ? HTTP_CATALOG : $this->config->get('config_url')); return $nat_base . 'image/' . str_replace('\\', '/', $filename); } } ]]> mime == 'image/gif') {]]> mime == 'image/webp' || $this->mime == 'image/vnd.webp' || $this->mime == 'image/x-webp') && function_exists('imagecreatefromwebp')) { $this->image = @imagecreatefromwebp($file); } else ]]> image, $file, $quality); } else ]]> image, $file, $quality);]]> image, true); ]]> get('config'); if ($config && $config->get('module_img_opti_status')) { $webp_on_fly = $config->get('module_img_opti_webp_on_fly'); $lazy_load = $config->get('module_img_opti_lazy_load'); $broken_fallback = $config->get('module_img_opti_broken_fallback'); $fallback_image = $config->get('module_img_opti_fallback_image'); $support_svg = $config->get('module_img_opti_support_svg'); $support_svg_autofix = ($config->get('module_img_opti_support_svg_autofix') !== null) ? $config->get('module_img_opti_support_svg_autofix') : 1; $theme = $config->get('config_theme'); $additional_width = 0; $additional_height = 0; $thumb_width = 0; $thumb_height = 0; if ($theme) { $additional_width = $config->get('theme_' . $theme . '_image_additional_width'); $additional_height = $config->get('theme_' . $theme . '_image_additional_height'); $thumb_width = $config->get('theme_' . $theme . '_image_thumb_width'); $thumb_height = $config->get('theme_' . $theme . '_image_thumb_height'); } if (!$additional_width) { $additional_width = $config->get('theme_default_image_additional_width'); } if (!$additional_height) { $additional_height = $config->get('theme_default_image_additional_height'); } if (!$thumb_width) { $thumb_width = $config->get('theme_default_image_thumb_width'); } if (!$thumb_height) { $thumb_height = $config->get('theme_default_image_thumb_height'); } if (!$additional_width) { $additional_width = $config->get('config_image_additional_width'); } if (!$additional_height) { $additional_height = $config->get('config_image_additional_height'); } if (!$thumb_width) { $thumb_width = $config->get('config_image_thumb_width'); } if (!$thumb_height) { $thumb_height = $config->get('config_image_thumb_height'); } if (!$additional_width) { $additional_width = 74; } if (!$additional_height) { $additional_height = 74; } if (!$thumb_width) { $thumb_width = 228; } if (!$thumb_height) { $thumb_height = 228; } if ($support_svg && $support_svg_autofix) { $svg_style = ''; $output = str_ireplace('', $svg_style . '', $output); } if ($webp_on_fly || $lazy_load || $broken_fallback) { $registry->get('load')->model('tool/image'); $model_tool_image = $registry->get('model_tool_image'); if ($webp_on_fly) { $output = preg_replace_callback('/]*)>/is', function($matches) use ($config, $registry, $model_tool_image, $webp_on_fly) { $attrs_str = $matches[1]; preg_match_all('/(\b[\w\-:]+)\s*=\s*(?:"([^"]*)"|\'([^\']*)\'|([^\s>]+))/is', $attrs_str, $attr_matches, PREG_SET_ORDER); $attrs = array(); foreach ($attr_matches as $am) { $name = strtolower($am[1]); $val = ($am[2] !== '') ? $am[2] : (($am[3] !== '') ? $am[3] : $am[4]); $attrs[$name] = $val; } if (!empty($attrs['href'])) { $href = $attrs['href']; $rel_path = ''; if (preg_match('/\\/image\\/(.*\\.(?:jpg|jpeg|png))/is', $href, $m_rel)) { $rel_path = urldecode($m_rel[1]); } elseif (preg_match('/^image\\/(.*\\.(?:jpg|jpeg|png))/is', $href, $m_rel)) { $rel_path = urldecode($m_rel[1]); } $clean_rel_path = preg_replace('/\\?.*/', '', $rel_path); $browser_supports_webp = isset($_SERVER['HTTP_ACCEPT']) && (strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') !== false); if ($browser_supports_webp && $clean_rel_path) { $ext = strtolower(substr(strrchr($clean_rel_path, '.'), 1)); $phys_source = DIR_IMAGE . $clean_rel_path; $phys_webp = DIR_IMAGE . preg_replace('/\\.(jpg|jpeg|png)$/i', '.webp', $clean_rel_path); if (file_exists($phys_source)) { if (!file_exists($phys_webp)) { $img_data = @file_get_contents($phys_source); if ($img_data) { $im = @imagecreatefromstring($img_data); if ($im) { $webp_quality = (int)$config->get('module_img_opti_webp_quality'); if ($webp_quality <= 0 || $webp_quality > 100) { $webp_quality = 80; } @imagewebp($im, $phys_webp, $webp_quality); @imagedestroy($im); } } } if (file_exists($phys_webp)) { $attrs['href'] = preg_replace('/\\.(jpg|jpeg|png)(\\?|$)/i', '.webp$2', $attrs['href']); } } } } $new_attrs = array(); foreach ($attrs as $k => $v) { $new_attrs[] = $k . '="' . htmlspecialchars($v, ENT_QUOTES, 'UTF-8') . '"'; } return ''; }, $output); } $output = preg_replace_callback('/]*)>/is', function($matches) use ($config, $registry, $model_tool_image, $webp_on_fly, $lazy_load, $broken_fallback, $fallback_image) { $attrs_str = $matches[1]; if (stripos($attrs_str, 'catalog_trash') !== false) { return $matches[0]; } preg_match_all('/(\b[\w\-:]+)\s*=\s*(?:"([^"]*)"|\'([^\']*)\'|([^\s>]+))/is', $attrs_str, $attr_matches, PREG_SET_ORDER); $attrs = array(); foreach ($attr_matches as $am) { $name = strtolower($am[1]); $val = ($am[2] !== '') ? $am[2] : (($am[3] !== '') ? $am[3] : $am[4]); $attrs[$name] = $val; } $src = isset($attrs['src']) ? $attrs['src'] : ''; $data_src = isset($attrs['data-src']) ? $attrs['data-src'] : ''; $has_datasrc = ($data_src !== ''); $target_url = $has_datasrc ? $data_src : $src; $rel_path = ''; if (preg_match('/\\/image\\/(.*\\.(?:jpg|jpeg|png|webp|svg))/is', $target_url, $m_rel)) { $rel_path = urldecode($m_rel[1]); } elseif (preg_match('/^image\\/(.*\\.(?:jpg|jpeg|png|webp|svg))/is', $target_url, $m_rel)) { $rel_path = urldecode($m_rel[1]); } $clean_rel_path = preg_replace('/\\?.*/', '', $rel_path); $browser_supports_webp = isset($_SERVER['HTTP_ACCEPT']) && (strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') !== false); if ($webp_on_fly && $browser_supports_webp && $clean_rel_path) { $ext = strtolower(substr(strrchr($clean_rel_path, '.'), 1)); if (in_array($ext, array('jpg', 'jpeg', 'png'))) { $phys_source = DIR_IMAGE . $clean_rel_path; $phys_webp = DIR_IMAGE . preg_replace('/\\.(jpg|jpeg|png)$/i', '.webp', $clean_rel_path); if (file_exists($phys_source)) { if (!file_exists($phys_webp)) { $img_data = @file_get_contents($phys_source); if ($img_data) { $im = @imagecreatefromstring($img_data); if ($im) { $webp_quality = (int)$config->get('module_img_opti_webp_quality'); if ($webp_quality <= 0 || $webp_quality > 100) { $webp_quality = 80; } @imagewebp($im, $phys_webp, $webp_quality); @imagedestroy($im); } } } if (file_exists($phys_webp)) { if (isset($attrs['src'])) { $attrs['src'] = preg_replace('/\\.(jpg|jpeg|png)(\\?|$)/i', '.webp$2', $attrs['src']); } if (isset($attrs['data-src'])) { $attrs['data-src'] = preg_replace('/\\.(jpg|jpeg|png)(\\?|$)/i', '.webp$2', $attrs['data-src']); } } } } } if ($webp_on_fly && $browser_supports_webp) { foreach (array('srcset', 'data-srcset') as $srcset_attr) { if (isset($attrs[$srcset_attr])) { $parts = explode(',', $attrs[$srcset_attr]); foreach ($parts as &$part) { $part = trim($part); $subparts = preg_split('/\\s+/', $part); if (!empty($subparts[0])) { $s_url = $subparts[0]; $s_rel = ''; if (preg_match('/\\/image\\/(.*\\.(?:jpg|jpeg|png|webp|svg))/is', $s_url, $sm_rel)) { $s_rel = urldecode($sm_rel[1]); } elseif (preg_match('/^image\\/(.*\\.(?:jpg|jpeg|png|webp|svg))/is', $s_url, $sm_rel)) { $s_rel = urldecode($sm_rel[1]); } $s_clean = preg_replace('/\\?.*/', '', $s_rel); if ($s_clean) { $s_ext = strtolower(substr(strrchr($s_clean, '.'), 1)); if (in_array($s_ext, array('jpg', 'jpeg', 'png'))) { $s_phys_source = DIR_IMAGE . $s_clean; $s_phys_webp = DIR_IMAGE . preg_replace('/\\.(jpg|jpeg|png)$/i', '.webp', $s_clean); if (file_exists($s_phys_source)) { if (!file_exists($s_phys_webp)) { $img_data = @file_get_contents($s_phys_source); if ($img_data) { $im = @imagecreatefromstring($img_data); if ($im) { $webp_quality = (int)$config->get('module_img_opti_webp_quality'); if ($webp_quality <= 0 || $webp_quality > 100) { $webp_quality = 80; } @imagewebp($im, $s_phys_webp, $webp_quality); @imagedestroy($im); } } } if (file_exists($s_phys_webp)) { $subparts[0] = preg_replace('/\\.(jpg|jpeg|png)(\\?|$)/i', '.webp$2', $s_url); } } } } } $part = implode(' ', $subparts); } $attrs[$srcset_attr] = implode(', ', $parts); } } } $is_svg = (strtolower(substr(strrchr($clean_rel_path, '.'), 1)) === 'svg'); if ($lazy_load && $clean_rel_path && is_file(DIR_IMAGE . $clean_rel_path) && !$is_svg) { try { $tiny_thumb = $model_tool_image->resize($clean_rel_path, 20, 20); if ($has_datasrc) { $attrs['src'] = $tiny_thumb; } else { $attrs['data-src'] = isset($attrs['src']) ? $attrs['src'] : ''; $attrs['src'] = $tiny_thumb; } if (isset($attrs['srcset'])) { $attrs['data-srcset'] = $attrs['srcset']; unset($attrs['srcset']); } $class = isset($attrs['class']) ? $attrs['class'] . ' img-lazyload' : 'img-lazyload'; $attrs['class'] = $class; $style = 'filter: blur(10px); transition: filter 0.3s;'; if (isset($attrs['style'])) { $attrs['style'] = rtrim(trim($attrs['style']), ';') . '; ' . $style; } else { $attrs['style'] = $style; } } catch (Exception $e) {} } if ($broken_fallback) { $fallback_url = ''; $req_obj = $registry->get('request'); $is_https = isset($req_obj->server['HTTPS']) && ($req_obj->server['HTTPS'] == 'on' || $req_obj->server['HTTPS'] == '1'); $server_url = $is_https ? $config->get('config_ssl') : $config->get('config_url'); if ($fallback_image && is_file(DIR_IMAGE . $fallback_image)) { $fallback_url = $server_url . 'image/' . $fallback_image; } elseif ($config->get('config_logo') && is_file(DIR_IMAGE . $config->get('config_logo'))) { $fallback_url = $server_url . 'image/' . $config->get('config_logo'); } else { $fallback_url = $server_url . 'image/no_image.png'; } if ($fallback_url) { $attrs['onerror'] = "this.src='" . $fallback_url . "'; this.srcset=''; this.onerror=null;"; } } $new_attrs = array(); foreach ($attrs as $k => $v) { $new_attrs[] = $k . '="' . htmlspecialchars($v, ENT_QUOTES, 'UTF-8') . '"'; } return ''; }, $output); if ($lazy_load) { $lazy_script = ' '; $output = str_ireplace('', $lazy_script, $output); } } } } ]]> model_tool_image->resize($product_info['image'], $this->config->get('theme_' . $this->config->get('config_theme') . '_image_popup_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_popup_height')); } else { $data['popup'] = ''; }]]> config->get('module_img_opti_status') && $this->config->get('module_img_opti_broken_fallback') && $this->config->get('module_img_opti_fallback_image'))) { $data['popup'] = $this->model_tool_image->resize($product_info['image'], $this->config->get('theme_' . $this->config->get('config_theme') . '_image_popup_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_popup_height')); } else { $data['popup'] = ''; } ]]> model_tool_image->resize($product_info['image'], $this->config->get('theme_' . $this->config->get('config_theme') . '_image_thumb_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_thumb_height')); } else { $data['thumb'] = ''; }]]> config->get('module_img_opti_status') && $this->config->get('module_img_opti_broken_fallback') && $this->config->get('module_img_opti_fallback_image'))) { $data['thumb'] = $this->model_tool_image->resize($product_info['image'], $this->config->get('theme_' . $this->config->get('config_theme') . '_image_thumb_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_thumb_height')); } else { $data['thumb'] = ''; } ]]> array('image/jpeg', 'image/png','image/webp', 'image/gif', 'image/svg+xml',]]> ($this->config->get('module_img_opti_status') && $this->config->get('module_img_opti_support_webp')) ? array('image/jpeg', 'image/png', 'image/webp', 'image/gif', 'image/svg+xml', 'image/pjpeg', 'image/x-png') : array('image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/pjpeg', 'image/x-png'),]]> 'psd']]> 'webp', 'image/vnd.webp' => 'webp', 'image/x-webp' => 'webp']]>