fix(watermark): add interactive HTML5 colorpicker, unique cache-busted preview filenames and exact product canvas aspect ratio
This commit is contained in:
parent
c7eec6d352
commit
2a9e4c3769
Binary file not shown.
|
|
@ -6,7 +6,11 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
private $translations = array();
|
private $translations = array();
|
||||||
|
|
||||||
public function index() {
|
public function index() {
|
||||||
$data = $this->load->language('module/img_opti');
|
$lang_data = $this->load->language('module/img_opti');
|
||||||
|
if (!is_array($lang_data)) {
|
||||||
|
$lang_data = array();
|
||||||
|
}
|
||||||
|
$data = array_merge($this->loadLanguageSafe(), $lang_data);
|
||||||
$this->document->setTitle($this->language->get('heading_title_raw'));
|
$this->document->setTitle($this->language->get('heading_title_raw'));
|
||||||
|
|
||||||
$this->load->model('setting/setting');
|
$this->load->model('setting/setting');
|
||||||
|
|
@ -95,6 +99,7 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
'module_img_opti_cron_webp_quality' => 80,
|
'module_img_opti_cron_webp_quality' => 80,
|
||||||
'module_img_opti_cron_max_width' => 1600,
|
'module_img_opti_cron_max_width' => 1600,
|
||||||
'module_img_opti_cron_max_height' => 1600,
|
'module_img_opti_cron_max_height' => 1600,
|
||||||
|
'module_img_opti_cron_batch_limit' => 100,
|
||||||
'module_img_opti_cron_tasks' => '',
|
'module_img_opti_cron_tasks' => '',
|
||||||
'module_img_opti_wm_type' => 'image',
|
'module_img_opti_wm_type' => 'image',
|
||||||
'module_img_opti_wm_image' => '',
|
'module_img_opti_wm_image' => '',
|
||||||
|
|
@ -145,9 +150,12 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
'module_img_opti_disk_quota_total' => 0,
|
'module_img_opti_disk_quota_total' => 0,
|
||||||
'module_img_opti_disk_quota_used' => 0,
|
'module_img_opti_disk_quota_used' => 0,
|
||||||
'module_img_opti_disk_status' => 0,
|
'module_img_opti_disk_status' => 0,
|
||||||
|
'module_img_opti_grid_limit' => 50,
|
||||||
'module_img_opti_wm_max_width' => 0,
|
'module_img_opti_wm_max_width' => 0,
|
||||||
'module_img_opti_wm_max_height' => 0,
|
'module_img_opti_wm_max_height' => 0,
|
||||||
'module_img_opti_truefilemanager_webp'=> (is_file(DIR_APPLICATION . 'controller/common/truefilemanager.php') || is_file(DIR_SYSTEM . 'library/sitecreator/trueFileManager/ControllerCommonTrueFileManager.php')) ? 1 : 0
|
'module_img_opti_truefilemanager_webp'=> (is_file(DIR_APPLICATION . 'controller/common/truefilemanager.php') || is_file(DIR_SYSTEM . 'library/sitecreator/trueFileManager/ControllerCommonTrueFileManager.php')) ? 1 : 0,
|
||||||
|
'module_img_opti_auto_fake_jpg_guard' => 1,
|
||||||
|
'module_img_opti_fake_jpg_mode' => 'jpg'
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($fields as $key => $default) {
|
foreach ($fields as $key => $default) {
|
||||||
|
|
@ -175,10 +183,22 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
'jpg_quality' => (int)$data['module_img_opti_cron_jpg_quality'],
|
'jpg_quality' => (int)$data['module_img_opti_cron_jpg_quality'],
|
||||||
'webp_quality' => (int)$data['module_img_opti_cron_webp_quality'],
|
'webp_quality' => (int)$data['module_img_opti_cron_webp_quality'],
|
||||||
'max_width' => (int)$data['module_img_opti_cron_max_width'],
|
'max_width' => (int)$data['module_img_opti_cron_max_width'],
|
||||||
'max_height' => (int)$data['module_img_opti_cron_max_height']
|
'max_height' => (int)$data['module_img_opti_cron_max_height'],
|
||||||
|
'batch_limit' => (int)$data['module_img_opti_cron_batch_limit']
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$data['module_img_opti_cron_tasks_json'] = json_encode($default_cron_tasks, JSON_UNESCAPED_UNICODE);
|
$data['module_img_opti_cron_tasks_json'] = json_encode($default_cron_tasks, JSON_UNESCAPED_UNICODE);
|
||||||
|
} else {
|
||||||
|
$cron_tasks_arr = json_decode(html_entity_decode($data['module_img_opti_cron_tasks'], ENT_QUOTES, 'UTF-8'), true);
|
||||||
|
if (is_array($cron_tasks_arr)) {
|
||||||
|
foreach ($cron_tasks_arr as &$t) {
|
||||||
|
if (!isset($t['batch_limit'])) {
|
||||||
|
$t['batch_limit'] = 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($t);
|
||||||
|
$data['module_img_opti_cron_tasks_json'] = json_encode($cron_tasks_arr, JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($data['module_img_opti_wm_rules'])) {
|
if (empty($data['module_img_opti_wm_rules'])) {
|
||||||
|
|
@ -431,6 +451,11 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$stats = $this->getModuleModel()->getGlobalStats();
|
||||||
|
$data['stats_files'] = number_format($stats['total_files'], 0, '.', ' ');
|
||||||
|
$data['stats_saved_mb'] = number_format($stats['saved_mb'], 2, '.', ' ');
|
||||||
|
$data['stats_avg_pct'] = number_format($stats['avg_pct'], 1, '.', ' ');
|
||||||
|
|
||||||
$data['header'] = $this->load->controller('common/header');
|
$data['header'] = $this->load->controller('common/header');
|
||||||
$data['column_left'] = $this->load->controller('common/column_left');
|
$data['column_left'] = $this->load->controller('common/column_left');
|
||||||
$data['footer'] = $this->load->controller('common/footer');
|
$data['footer'] = $this->load->controller('common/footer');
|
||||||
|
|
@ -438,6 +463,13 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
$this->response->setOutput($this->load->view('module/img_opti', $data));
|
$this->response->setOutput($this->load->view('module/img_opti', $data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getModuleModel() {
|
||||||
|
if (!isset($this->model_extension_module_img_opti)) {
|
||||||
|
$this->load->model('module/img_opti');
|
||||||
|
}
|
||||||
|
return $this->model_extension_module_img_opti;
|
||||||
|
}
|
||||||
|
|
||||||
public function autocomplete_category() {
|
public function autocomplete_category() {
|
||||||
$this->loadLanguageSafe();
|
$this->loadLanguageSafe();
|
||||||
if (!isset($this->request->get['user_token']) || !isset($this->session->data['user_token']) || $this->request->get['user_token'] !== $this->session->data['user_token']) {
|
if (!isset($this->request->get['user_token']) || !isset($this->session->data['user_token']) || $this->request->get['user_token'] !== $this->session->data['user_token']) {
|
||||||
|
|
@ -553,10 +585,35 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
file_put_contents(DIR_CACHE . 'img_opti_queue.json', json_encode($allFiles, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR));
|
file_put_contents(DIR_CACHE . 'img_opti_queue.json', json_encode($allFiles, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR));
|
||||||
$json['total'] = count($allFiles);
|
$json['total'] = count($allFiles);
|
||||||
$json['success'] = $this->language->get('text_found') . $json['total'];
|
$json['success'] = $this->language->get('text_found') . $json['total'];
|
||||||
|
$json['log'] = array("<div style='border-bottom:1px solid #333; padding:2px 0;'><span class='text-success'>" . htmlspecialchars($json['success'], ENT_QUOTES | ENT_IGNORE, 'UTF-8') . "</span></div>");
|
||||||
|
file_put_contents(DIR_CACHE . 'img_opti_opti_scan_summary.json', json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR));
|
||||||
|
@unlink(DIR_CACHE . 'img_opti_process_state.json');
|
||||||
|
|
||||||
$this->response->setOutput(json_encode($json));
|
$this->response->setOutput(json_encode($json));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_cached_opti() {
|
||||||
|
$this->loadLanguageSafe();
|
||||||
|
$this->response->addHeader('Content-Type: application/json');
|
||||||
|
$state_file = DIR_CACHE . 'img_opti_process_state.json';
|
||||||
|
if (file_exists($state_file)) {
|
||||||
|
$state = json_decode(file_get_contents($state_file), true);
|
||||||
|
if ($state) {
|
||||||
|
$this->response->setOutput(json_encode($state));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$summary_file = DIR_CACHE . 'img_opti_opti_scan_summary.json';
|
||||||
|
if (file_exists($summary_file)) {
|
||||||
|
$json = json_decode(file_get_contents($summary_file), true);
|
||||||
|
if ($json) {
|
||||||
|
$this->response->setOutput(json_encode($json));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->response->setOutput(json_encode(array('total' => 0, 'success' => '')));
|
||||||
|
}
|
||||||
|
|
||||||
public function process() {
|
public function process() {
|
||||||
$this->loadLanguageSafe();
|
$this->loadLanguageSafe();
|
||||||
if (!isset($this->request->get['user_token']) || !isset($this->session->data['user_token']) || $this->request->get['user_token'] !== $this->session->data['user_token']) {
|
if (!isset($this->request->get['user_token']) || !isset($this->session->data['user_token']) || $this->request->get['user_token'] !== $this->session->data['user_token']) {
|
||||||
|
|
@ -577,6 +634,7 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
session_write_close();
|
session_write_close();
|
||||||
|
|
||||||
if (!file_exists($queueFile)) {
|
if (!file_exists($queueFile)) {
|
||||||
|
$this->markProcessFinishedState();
|
||||||
$json['finished'] = true;
|
$json['finished'] = true;
|
||||||
$this->response->setOutput(json_encode($json));
|
$this->response->setOutput(json_encode($json));
|
||||||
return;
|
return;
|
||||||
|
|
@ -601,6 +659,7 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
flock($fp, LOCK_UN);
|
flock($fp, LOCK_UN);
|
||||||
fclose($fp);
|
fclose($fp);
|
||||||
@unlink($queueFile);
|
@unlink($queueFile);
|
||||||
|
$this->markProcessFinishedState();
|
||||||
$json['finished'] = true;
|
$json['finished'] = true;
|
||||||
$this->response->setOutput(json_encode($json));
|
$this->response->setOutput(json_encode($json));
|
||||||
return;
|
return;
|
||||||
|
|
@ -804,13 +863,62 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
$json['batch_old'] = $batchOldSize;
|
$json['batch_old'] = $batchOldSize;
|
||||||
$json['batch_new'] = $batchNewSize;
|
$json['batch_new'] = $batchNewSize;
|
||||||
|
|
||||||
if (!file_exists($queueFile)) {
|
if ($batchOptimized > 0 && $batchOldSize > $batchNewSize) {
|
||||||
|
$bytesSaved = $batchOldSize - $batchNewSize;
|
||||||
|
$this->getModuleModel()->recordGlobalStats($batchOptimized, $bytesSaved, $batchOldSize, 'manual_opti');
|
||||||
|
}
|
||||||
|
$globalStats = $this->getModuleModel()->getGlobalStats();
|
||||||
|
$json['stats'] = array(
|
||||||
|
'files' => number_format($globalStats['total_files'], 0, '.', ' '),
|
||||||
|
'saved_mb' => number_format($globalStats['saved_mb'], 2, '.', ' '),
|
||||||
|
'avg_pct' => number_format($globalStats['avg_pct'], 1, '.', ' ')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!file_exists($queueFile) || empty($queue)) {
|
||||||
$json['finished'] = true;
|
$json['finished'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$stateFile = DIR_CACHE . 'img_opti_process_state.json';
|
||||||
|
$state = array('total' => 0, 'processed' => 0, 'optimized' => 0, 'old_bytes' => 0, 'new_bytes' => 0, 'finished' => false, 'log' => array(), 'mode' => $mode, 'copy_folder' => $copyFolder);
|
||||||
|
if (file_exists($stateFile)) {
|
||||||
|
$prev = json_decode(file_get_contents($stateFile), true);
|
||||||
|
if ($prev) $state = array_merge($prev, $state);
|
||||||
|
}
|
||||||
|
$state['mode'] = $mode;
|
||||||
|
$state['copy_folder'] = $copyFolder;
|
||||||
|
$state['processed'] += $processed;
|
||||||
|
$state['optimized'] += $batchOptimized;
|
||||||
|
$state['old_bytes'] += $batchOldSize;
|
||||||
|
$state['new_bytes'] += $batchNewSize;
|
||||||
|
if (!empty($json['log'])) {
|
||||||
|
$state['log'] = array_merge($state['log'], $json['log']);
|
||||||
|
}
|
||||||
|
if (!empty($json['finished'])) {
|
||||||
|
$state['finished'] = true;
|
||||||
|
}
|
||||||
|
$scanSummary = DIR_CACHE . 'img_opti_opti_scan_summary.json';
|
||||||
|
if (file_exists($scanSummary)) {
|
||||||
|
$scan = json_decode(file_get_contents($scanSummary), true);
|
||||||
|
if ($scan && isset($scan['total'])) {
|
||||||
|
$state['total'] = $scan['total'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_put_contents($stateFile, json_encode($state, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR));
|
||||||
|
|
||||||
$this->response->setOutput(json_encode($json));
|
$this->response->setOutput(json_encode($json));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function markProcessFinishedState() {
|
||||||
|
$stateFile = DIR_CACHE . 'img_opti_process_state.json';
|
||||||
|
if (file_exists($stateFile)) {
|
||||||
|
$state = json_decode(file_get_contents($stateFile), true);
|
||||||
|
if ($state) {
|
||||||
|
$state['finished'] = true;
|
||||||
|
file_put_contents($stateFile, json_encode($state, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function applyChanges() {
|
public function applyChanges() {
|
||||||
$this->loadLanguageSafe();
|
$this->loadLanguageSafe();
|
||||||
if (!isset($this->request->get['user_token']) || !isset($this->session->data['user_token']) || $this->request->get['user_token'] !== $this->session->data['user_token']) {
|
if (!isset($this->request->get['user_token']) || !isset($this->session->data['user_token']) || $this->request->get['user_token'] !== $this->session->data['user_token']) {
|
||||||
|
|
@ -934,8 +1042,6 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
$this->saveOptimizedCache($cache);
|
$this->saveOptimizedCache($cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->recursiveDelete($source_dir);
|
|
||||||
|
|
||||||
$msg = $this->language->get('text_apply_success');
|
$msg = $this->language->get('text_apply_success');
|
||||||
$msg .= $do_backup ? $this->language->get('text_apply_backup_ok') . htmlspecialchars($backup_name, ENT_QUOTES, 'UTF-8') : $this->language->get('text_apply_no_backup');
|
$msg .= $do_backup ? $this->language->get('text_apply_backup_ok') . htmlspecialchars($backup_name, ENT_QUOTES, 'UTF-8') : $this->language->get('text_apply_no_backup');
|
||||||
|
|
||||||
|
|
@ -945,6 +1051,10 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
$json['success'] = $msg;
|
$json['success'] = $msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@unlink(DIR_CACHE . 'img_opti_process_state.json');
|
||||||
|
@unlink(DIR_CACHE . 'img_opti_opti_scan_summary.json');
|
||||||
|
@unlink(DIR_CACHE . 'img_opti_queue.json');
|
||||||
|
|
||||||
$this->response->setOutput(json_encode($json));
|
$this->response->setOutput(json_encode($json));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1011,6 +1121,41 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
|
|
||||||
$json['success'] = $this->language->get('text_quarantine_empty');
|
$json['success'] = $this->language->get('text_quarantine_empty');
|
||||||
|
|
||||||
|
@unlink(DIR_CACHE . 'img_opti_process_state.json');
|
||||||
|
@unlink(DIR_CACHE . 'img_opti_opti_scan_summary.json');
|
||||||
|
@unlink(DIR_CACHE . 'img_opti_queue.json');
|
||||||
|
|
||||||
|
$this->response->setOutput(json_encode($json));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save_grid_limit() {
|
||||||
|
$this->loadLanguageSafe();
|
||||||
|
$json = array();
|
||||||
|
|
||||||
|
if (!isset($this->request->get['user_token']) || !isset($this->session->data['user_token']) || $this->request->get['user_token'] !== $this->session->data['user_token']) {
|
||||||
|
$json['error'] = $this->language->get('error_permission');
|
||||||
|
$this->response->setOutput(json_encode($json));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->user->hasPermission('modify', 'module/img_opti')) {
|
||||||
|
$json['error'] = $this->language->get('error_permission');
|
||||||
|
$this->response->setOutput(json_encode($json));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$limit = isset($this->request->post['limit']) ? max(1, (int)$this->request->post['limit']) : 50;
|
||||||
|
|
||||||
|
$query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "setting` WHERE `code` = 'module_img_opti' AND `key` = 'module_img_opti_grid_limit' AND `store_id` = '0'");
|
||||||
|
if ($query->num_rows) {
|
||||||
|
$this->db->query("UPDATE `" . DB_PREFIX . "setting` SET `value` = '" . (int)$limit . "' WHERE `code` = 'module_img_opti' AND `key` = 'module_img_opti_grid_limit' AND `store_id` = '0'");
|
||||||
|
} else {
|
||||||
|
$this->db->query("INSERT INTO `" . DB_PREFIX . "setting` SET `code` = 'module_img_opti', `key` = 'module_img_opti_grid_limit', `value` = '" . (int)$limit . "', `serialized` = '0', `store_id` = '0'");
|
||||||
|
}
|
||||||
|
|
||||||
|
$json['success'] = true;
|
||||||
|
$json['limit'] = $limit;
|
||||||
|
|
||||||
$this->response->setOutput(json_encode($json));
|
$this->response->setOutput(json_encode($json));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1099,7 +1244,7 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
$tool = isset($this->request->post['tool']) ? preg_replace('/[^a-zA-Z0-9_]/', '', (string)$this->request->post['tool']) : '';
|
$tool = isset($this->request->post['tool']) ? preg_replace('/[^a-zA-Z0-9_]/', '', (string)$this->request->post['tool']) : '';
|
||||||
|
|
||||||
$this->load->model('module/img_opti');
|
$this->load->model('module/img_opti');
|
||||||
$json = $this->model_module_img_opti->generateCompareUrls($tool, $id);
|
$json = $this->model_extension_module_img_opti->generateCompareUrls($tool, $id);
|
||||||
|
|
||||||
$this->response->addHeader('Content-Type: application/json');
|
$this->response->addHeader('Content-Type: application/json');
|
||||||
$this->response->setOutput(json_encode($json));
|
$this->response->setOutput(json_encode($json));
|
||||||
|
|
@ -1362,6 +1507,23 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function reset_stats() {
|
||||||
|
$this->loadLanguageSafe();
|
||||||
|
if (!isset($this->request->get['user_token']) || !isset($this->session->data['user_token']) || $this->request->get['user_token'] !== $this->session->data['user_token']) {
|
||||||
|
$this->response->addHeader('Content-Type: application/json');
|
||||||
|
$this->response->setOutput(json_encode(array('error' => $this->language->get('error_permission'))));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$newStats = $this->getModuleModel()->resetGlobalStats();
|
||||||
|
$this->response->addHeader('Content-Type: application/json');
|
||||||
|
$this->response->setOutput(json_encode(array(
|
||||||
|
'success' => true,
|
||||||
|
'files' => number_format($newStats['total_files'], 0, '.', ' '),
|
||||||
|
'saved_mb' => number_format($newStats['saved_mb'], 2, '.', ' '),
|
||||||
|
'avg_pct' => number_format($newStats['avg_pct'], 1, '.', ' ')
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
public function run_tool() {
|
public function run_tool() {
|
||||||
$this->loadLanguageSafe();
|
$this->loadLanguageSafe();
|
||||||
if (!isset($this->request->get['user_token']) || !isset($this->session->data['user_token']) || $this->request->get['user_token'] !== $this->session->data['user_token']) {
|
if (!isset($this->request->get['user_token']) || !isset($this->session->data['user_token']) || $this->request->get['user_token'] !== $this->session->data['user_token']) {
|
||||||
|
|
@ -1391,12 +1553,19 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
|
|
||||||
$this->load->model('module/img_opti');
|
$this->load->model('module/img_opti');
|
||||||
|
|
||||||
|
if ($action === 'get_cached_grid') {
|
||||||
|
$method = 'get_cached_grid';
|
||||||
|
} elseif ($action === 'preview_black_bg_row') {
|
||||||
|
$method = 'preview_black_bg_row';
|
||||||
|
} else {
|
||||||
$method = $action . '_' . $tool;
|
$method = $action . '_' . $tool;
|
||||||
if ($tool === 'broken') {
|
if ($tool === 'broken') {
|
||||||
$method = $action . '_broken_db';
|
$method = $action . '_broken_db';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$allowed_methods = array(
|
$allowed_methods = array(
|
||||||
|
'get_cached_grid',
|
||||||
'scan_broken_db', 'fix_broken_db',
|
'scan_broken_db', 'fix_broken_db',
|
||||||
'scan_broken_files', 'fix_broken_files',
|
'scan_broken_files', 'fix_broken_files',
|
||||||
'scan_duplicates', 'fix_duplicates',
|
'scan_duplicates', 'fix_duplicates',
|
||||||
|
|
@ -1409,15 +1578,33 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
'scan_placeholders', 'fix_placeholders',
|
'scan_placeholders', 'fix_placeholders',
|
||||||
'scan_watermark',
|
'scan_watermark',
|
||||||
'scan_small_photos', 'fix_small_photos',
|
'scan_small_photos', 'fix_small_photos',
|
||||||
'scan_html_broken',
|
'scan_html_broken', 'fix_html_broken',
|
||||||
'scan_folder_tree', 'fix_folder_tree',
|
'scan_folder_tree', 'fix_folder_tree',
|
||||||
'scan_sanitizer', 'fix_sanitizer',
|
'scan_sanitizer', 'fix_sanitizer',
|
||||||
'scan_cmyk', 'fix_cmyk',
|
'scan_cmyk', 'fix_cmyk',
|
||||||
'scan_heavy_files', 'fix_heavy_files'
|
'scan_heavy_files', 'fix_heavy_files',
|
||||||
|
'scan_svg_security', 'fix_svg_security',
|
||||||
|
'scan_black_bg', 'fix_black_bg', 'preview_black_bg_row'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (in_array($method, $allowed_methods)) {
|
if (in_array($method, $allowed_methods)) {
|
||||||
$json = $this->model_module_img_opti->{$method}($this->request->post);
|
$start = isset($this->request->post['start']) ? max(0, (int)$this->request->post['start']) : 0;
|
||||||
|
$limit = isset($this->request->post['limit']) ? max(0, (int)$this->request->post['limit']) : 0;
|
||||||
|
$page = isset($this->request->post['page']) ? max(1, (int)$this->request->post['page']) : 1;
|
||||||
|
|
||||||
|
if ($limit > 0 && $start === 0 && $page > 1) {
|
||||||
|
$start = ($page - 1) * $limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->request->post['start'] = $start;
|
||||||
|
$this->request->post['limit'] = $limit;
|
||||||
|
|
||||||
|
$json = $this->model_extension_module_img_opti->{$method}($this->request->post);
|
||||||
|
|
||||||
|
if (isset($json['total']) && $limit > 0) {
|
||||||
|
$json['page'] = floor($start / $limit) + 1;
|
||||||
|
$json['pages'] = max(1, ceil($json['total'] / $limit));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$json['error'] = 'Tool method not found: ' . $method;
|
$json['error'] = 'Tool method not found: ' . $method;
|
||||||
}
|
}
|
||||||
|
|
@ -1500,7 +1687,7 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
'limit' => isset($this->request->post['limit']) ? (int)$this->request->post['limit'] : 200
|
'limit' => isset($this->request->post['limit']) ? (int)$this->request->post['limit'] : 200
|
||||||
);
|
);
|
||||||
|
|
||||||
$json = $this->model_module_img_opti->scan_broken_db($data);
|
$json = $this->model_extension_module_img_opti->scan_broken_db($data);
|
||||||
$this->response->addHeader('Content-Type: application/json');
|
$this->response->addHeader('Content-Type: application/json');
|
||||||
$this->response->setOutput(json_encode($json));
|
$this->response->setOutput(json_encode($json));
|
||||||
}
|
}
|
||||||
|
|
@ -1536,7 +1723,7 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
'fix_all' => isset($this->request->post['fix_all']) ? (int)$this->request->post['fix_all'] : 0
|
'fix_all' => isset($this->request->post['fix_all']) ? (int)$this->request->post['fix_all'] : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->model_module_img_opti->fix_broken_db($data);
|
$this->model_extension_module_img_opti->fix_broken_db($data);
|
||||||
$json['success'] = true;
|
$json['success'] = true;
|
||||||
|
|
||||||
$this->response->addHeader('Content-Type: application/json');
|
$this->response->addHeader('Content-Type: application/json');
|
||||||
|
|
@ -1743,9 +1930,24 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
|
|
||||||
file_put_contents(DIR_CACHE . 'img_opti_trash_queue.json', json_encode($trashFiles, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR));
|
file_put_contents(DIR_CACHE . 'img_opti_trash_queue.json', json_encode($trashFiles, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR));
|
||||||
$json['total'] = count($trashFiles);
|
$json['total'] = count($trashFiles);
|
||||||
|
file_put_contents(DIR_CACHE . 'img_opti_trash_scan_summary.json', json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR));
|
||||||
$this->response->setOutput(json_encode($json));
|
$this->response->setOutput(json_encode($json));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_cached_trash() {
|
||||||
|
$this->loadLanguageSafe();
|
||||||
|
$this->response->addHeader('Content-Type: application/json');
|
||||||
|
$summary_file = DIR_CACHE . 'img_opti_trash_scan_summary.json';
|
||||||
|
if (file_exists($summary_file)) {
|
||||||
|
$json = json_decode(file_get_contents($summary_file), true);
|
||||||
|
if ($json) {
|
||||||
|
$this->response->setOutput(json_encode($json));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->response->setOutput(json_encode(array('total' => 0, 'total_bytes' => 0, 'log' => array())));
|
||||||
|
}
|
||||||
|
|
||||||
public function process_trash() {
|
public function process_trash() {
|
||||||
$this->loadLanguageSafe();
|
$this->loadLanguageSafe();
|
||||||
if (!isset($this->request->get['user_token']) || !isset($this->session->data['user_token']) || $this->request->get['user_token'] !== $this->session->data['user_token']) {
|
if (!isset($this->request->get['user_token']) || !isset($this->session->data['user_token']) || $this->request->get['user_token'] !== $this->session->data['user_token']) {
|
||||||
|
|
@ -1840,6 +2042,7 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
file_put_contents($queueFile, json_encode($queue, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR));
|
file_put_contents($queueFile, json_encode($queue, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR));
|
||||||
if (empty($queue)) {
|
if (empty($queue)) {
|
||||||
@unlink($queueFile);
|
@unlink($queueFile);
|
||||||
|
@unlink(DIR_CACHE . 'img_opti_trash_scan_summary.json');
|
||||||
$json['finished'] = true;
|
$json['finished'] = true;
|
||||||
}
|
}
|
||||||
$this->response->setOutput(json_encode($json));
|
$this->response->setOutput(json_encode($json));
|
||||||
|
|
@ -2014,20 +2217,34 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$temp_preview = DIR_IMAGE . 'cache/temp_wm_preview.png';
|
|
||||||
$compare_dir = DIR_IMAGE . 'cache/';
|
$compare_dir = DIR_IMAGE . 'cache/';
|
||||||
if (!is_dir($compare_dir)) {
|
if (!is_dir($compare_dir)) {
|
||||||
@mkdir($compare_dir, 0755, true);
|
@mkdir($compare_dir, 0755, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up old preview files older than 30 seconds
|
||||||
|
foreach (@glob($compare_dir . 'temp_wm_preview_*.png') as $old_file) {
|
||||||
|
if (is_file($old_file) && (time() - filemtime($old_file) > 30)) {
|
||||||
|
@unlink($old_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$preview_hash = md5(microtime(true) . rand(10000, 99999));
|
||||||
|
$temp_rel_path = 'cache/temp_wm_preview_' . $preview_hash . '.png';
|
||||||
|
$temp_preview = DIR_IMAGE . $temp_rel_path;
|
||||||
|
|
||||||
|
if ($bg_mode === 'white') {
|
||||||
$preview_w = 500;
|
$preview_w = 500;
|
||||||
$preview_h = 500;
|
$preview_h = 500;
|
||||||
$preview_im = imagecreatetruecolor($preview_w, $preview_h);
|
$preview_im = imagecreatetruecolor($preview_w, $preview_h);
|
||||||
|
|
||||||
if ($bg_mode === 'white') {
|
|
||||||
$white = imagecolorallocate($preview_im, 255, 255, 255);
|
$white = imagecolorallocate($preview_im, 255, 255, 255);
|
||||||
imagefill($preview_im, 0, 0, $white);
|
imagefill($preview_im, 0, 0, $white);
|
||||||
} elseif ($bg_mode === 'transparent') {
|
} elseif ($bg_mode === 'transparent') {
|
||||||
|
$preview_w = 500;
|
||||||
|
$preview_h = 500;
|
||||||
|
$preview_im = imagecreatetruecolor($preview_w, $preview_h);
|
||||||
|
imagealphablending($preview_im, false);
|
||||||
|
imagesavealpha($preview_im, true);
|
||||||
$c1 = imagecolorallocate($preview_im, 255, 255, 255);
|
$c1 = imagecolorallocate($preview_im, 255, 255, 255);
|
||||||
$c2 = imagecolorallocate($preview_im, 226, 232, 240);
|
$c2 = imagecolorallocate($preview_im, 226, 232, 240);
|
||||||
imagefill($preview_im, 0, 0, $c1);
|
imagefill($preview_im, 0, 0, $c1);
|
||||||
|
|
@ -2040,9 +2257,6 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$white = imagecolorallocate($preview_im, 255, 255, 255);
|
|
||||||
imagefill($preview_im, 0, 0, $white);
|
|
||||||
|
|
||||||
$base_img = false;
|
$base_img = false;
|
||||||
if (is_file($base_file)) {
|
if (is_file($base_file)) {
|
||||||
$ext = strtolower(pathinfo($base_file, PATHINFO_EXTENSION));
|
$ext = strtolower(pathinfo($base_file, PATHINFO_EXTENSION));
|
||||||
|
|
@ -2058,14 +2272,20 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
if ($base_img) {
|
if ($base_img) {
|
||||||
$orig_w = imagesx($base_img);
|
$orig_w = imagesx($base_img);
|
||||||
$orig_h = imagesy($base_img);
|
$orig_h = imagesy($base_img);
|
||||||
$scale = min($preview_w / $orig_w, $preview_h / $orig_h);
|
$max_side = 500;
|
||||||
$new_w = intval($orig_w * $scale);
|
$scale = min($max_side / max(1, $orig_w), $max_side / max(1, $orig_h));
|
||||||
$new_h = intval($orig_h * $scale);
|
$preview_w = max(10, intval($orig_w * $scale));
|
||||||
$dst_x = intval(($preview_w - $new_w) / 2);
|
$preview_h = max(10, intval($orig_h * $scale));
|
||||||
$dst_y = intval(($preview_h - $new_h) / 2);
|
|
||||||
|
|
||||||
imagecopyresampled($preview_im, $base_img, $dst_x, $dst_y, 0, 0, $new_w, $new_h, $orig_w, $orig_h);
|
$preview_im = imagecreatetruecolor($preview_w, $preview_h);
|
||||||
|
imagecopyresampled($preview_im, $base_img, 0, 0, 0, 0, $preview_w, $preview_h, $orig_w, $orig_h);
|
||||||
imagedestroy($base_img);
|
imagedestroy($base_img);
|
||||||
|
} else {
|
||||||
|
$preview_w = 500;
|
||||||
|
$preview_h = 500;
|
||||||
|
$preview_im = imagecreatetruecolor($preview_w, $preview_h);
|
||||||
|
$white = imagecolorallocate($preview_im, 255, 255, 255);
|
||||||
|
imagefill($preview_im, 0, 0, $white);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2093,12 +2313,12 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
$this->config->set('module_img_opti_wm_target_blog', 0);
|
$this->config->set('module_img_opti_wm_target_blog', 0);
|
||||||
|
|
||||||
$this->load->model('module/img_opti');
|
$this->load->model('module/img_opti');
|
||||||
$res = $this->model_module_img_opti->applyDynamicWatermark($temp_preview, '', true);
|
$res = $this->model_extension_module_img_opti->applyDynamicWatermark($temp_preview, '', true);
|
||||||
|
|
||||||
if ($res) {
|
if ($res) {
|
||||||
$catalog_url = (defined('HTTPS_CATALOG') && HTTPS_CATALOG) ? HTTPS_CATALOG : (defined('HTTP_CATALOG') ? HTTP_CATALOG : '');
|
$catalog_url = (defined('HTTPS_CATALOG') && HTTPS_CATALOG) ? HTTPS_CATALOG : (defined('HTTP_CATALOG') ? HTTP_CATALOG : '');
|
||||||
$json['success'] = true;
|
$json['success'] = true;
|
||||||
$json['preview_url'] = $catalog_url . 'image/cache/temp_wm_preview.png?t=' . time();
|
$json['preview_url'] = $catalog_url . 'image/' . $temp_rel_path . '?v=' . microtime(true);
|
||||||
} else {
|
} else {
|
||||||
$json['error'] = $this->language->get('error_wm_preview') ?: 'Failed to generate preview';
|
$json['error'] = $this->language->get('error_wm_preview') ?: 'Failed to generate preview';
|
||||||
}
|
}
|
||||||
|
|
@ -2373,12 +2593,69 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
die('Permission denied');
|
die('Permission denied');
|
||||||
}
|
}
|
||||||
$this->load->model('setting/setting');
|
$this->load->model('setting/setting');
|
||||||
$settings = $this->model_setting_setting->getSetting('module_img_opti');
|
$rawSettings = $this->model_setting_setting->getSetting('module_img_opti');
|
||||||
|
|
||||||
|
$allKeys = array(
|
||||||
|
'module_img_opti_status',
|
||||||
|
'module_img_opti_engine',
|
||||||
|
'module_img_opti_jpg_quality',
|
||||||
|
'module_img_opti_png_quality',
|
||||||
|
'module_img_opti_webp_quality',
|
||||||
|
'module_img_opti_max_width',
|
||||||
|
'module_img_opti_max_height',
|
||||||
|
'module_img_opti_convert_webp',
|
||||||
|
'module_img_opti_support_svg',
|
||||||
|
'module_img_opti_support_webp',
|
||||||
|
'module_img_opti_webp_on_fly',
|
||||||
|
'module_img_opti_lazy_load',
|
||||||
|
'module_img_opti_auto_fake_jpg_guard',
|
||||||
|
'module_img_opti_fake_jpg_mode',
|
||||||
|
'module_img_opti_broken_fallback',
|
||||||
|
'module_img_opti_fallback_image',
|
||||||
|
'module_img_opti_cron_tasks',
|
||||||
|
'module_img_opti_wm_status',
|
||||||
|
'module_img_opti_wm_rules',
|
||||||
|
'module_img_opti_wm_max_width',
|
||||||
|
'module_img_opti_wm_max_height',
|
||||||
|
'module_img_opti_ph_rules',
|
||||||
|
'module_img_opti_folder_rules',
|
||||||
|
'module_img_opti_log_level',
|
||||||
|
'module_img_opti_min_savings_bytes',
|
||||||
|
'module_img_opti_min_savings_percent',
|
||||||
|
'module_img_opti_heavy_limit',
|
||||||
|
'module_img_opti_heavy_min_size',
|
||||||
|
'module_img_opti_png_jpg_limit',
|
||||||
|
'module_img_opti_png_jpg_min_size',
|
||||||
|
'module_img_opti_sanitizer_limit',
|
||||||
|
'module_img_opti_grid_limit',
|
||||||
|
'module_img_opti_disk_quota_total',
|
||||||
|
'module_img_opti_disk_quota_used',
|
||||||
|
'module_img_opti_disk_status',
|
||||||
|
'module_img_opti_truefilemanager_webp'
|
||||||
|
);
|
||||||
|
|
||||||
|
$exportSettings = array();
|
||||||
|
foreach ($allKeys as $k) {
|
||||||
|
if (isset($rawSettings[$k])) {
|
||||||
|
$exportSettings[$k] = $rawSettings[$k];
|
||||||
|
} else {
|
||||||
|
$exportSettings[$k] = $this->config->get($k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($rawSettings)) {
|
||||||
|
foreach ($rawSettings as $k => $v) {
|
||||||
|
if (strpos($k, 'module_img_opti') === 0 && !isset($exportSettings[$k])) {
|
||||||
|
$exportSettings[$k] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$export = array(
|
$export = array(
|
||||||
'_module' => 'img_opti',
|
'_module' => 'img_opti',
|
||||||
'_version' => '1.2.0',
|
'_version' => '1.2.0',
|
||||||
'_exported' => date('Y-m-d H:i:s'),
|
'_exported' => date('Y-m-d H:i:s'),
|
||||||
'settings' => $settings
|
'settings' => $exportSettings
|
||||||
);
|
);
|
||||||
$filename = 'img_opti_settings_' . date('Ymd_His') . '.json';
|
$filename = 'img_opti_settings_' . date('Ymd_His') . '.json';
|
||||||
$this->response->addHeader('Content-Type: application/json');
|
$this->response->addHeader('Content-Type: application/json');
|
||||||
|
|
@ -2408,13 +2685,16 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
$json['error'] = $this->language->get('error_import_invalid');
|
$json['error'] = $this->language->get('error_import_invalid');
|
||||||
} else {
|
} else {
|
||||||
$this->load->model('setting/setting');
|
$this->load->model('setting/setting');
|
||||||
$safe = array();
|
$current = $this->model_setting_setting->getSetting('module_img_opti');
|
||||||
|
if (!is_array($current)) {
|
||||||
|
$current = array();
|
||||||
|
}
|
||||||
foreach ($data['settings'] as $key => $value) {
|
foreach ($data['settings'] as $key => $value) {
|
||||||
if (strpos($key, 'module_img_opti') === 0) {
|
if (strpos($key, 'module_img_opti') === 0) {
|
||||||
$safe[$key] = $value;
|
$current[$key] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->model_setting_setting->editSetting('module_img_opti', $safe);
|
$this->model_setting_setting->editSetting('module_img_opti', $current);
|
||||||
$this->cache->delete('img_opti_disk_stats');
|
$this->cache->delete('img_opti_disk_stats');
|
||||||
$json['success'] = true;
|
$json['success'] = true;
|
||||||
}
|
}
|
||||||
|
|
@ -2422,5 +2702,158 @@ class ControllerModuleImgOpti extends Controller {
|
||||||
$this->response->addHeader('Content-Type: application/json');
|
$this->response->addHeader('Content-Type: application/json');
|
||||||
$this->response->setOutput(json_encode($json));
|
$this->response->setOutput(json_encode($json));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function autoRotateImage($filePath, $im = null) {
|
||||||
|
if (!function_exists('exif_read_data')) {
|
||||||
|
return $im;
|
||||||
|
}
|
||||||
|
$ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
|
||||||
|
if (!in_array($ext, array('jpg', 'jpeg', 'tiff'))) {
|
||||||
|
return $im;
|
||||||
|
}
|
||||||
|
$exif = @exif_read_data($filePath);
|
||||||
|
if (!$exif || !isset($exif['Orientation'])) {
|
||||||
|
return $im;
|
||||||
|
}
|
||||||
|
$orientation = (int)$exif['Orientation'];
|
||||||
|
$angle = 0;
|
||||||
|
switch ($orientation) {
|
||||||
|
case 3:
|
||||||
|
$angle = 180;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
$angle = -90;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
$angle = 90;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ($angle !== 0) {
|
||||||
|
if ($im !== null) {
|
||||||
|
$im = @imagerotate($im, $angle, 0);
|
||||||
|
} else {
|
||||||
|
$img = @imagecreatefromjpeg($filePath);
|
||||||
|
if ($img) {
|
||||||
|
$img = @imagerotate($img, $angle, 0);
|
||||||
|
@imagejpeg($img, $filePath, 95);
|
||||||
|
@imagedestroy($img);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $im;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function convertPngToJpgClean($sourcePngPath, $targetJpgPath, $quality = 100, $bgColorHex = '#ffffff') {
|
||||||
|
$img = @imagecreatefrompng($sourcePngPath);
|
||||||
|
if (!$img) return false;
|
||||||
|
|
||||||
|
if (function_exists('imagepalettetotruecolor') && !imageistruecolor($img)) {
|
||||||
|
imagepalettetotruecolor($img);
|
||||||
|
}
|
||||||
|
|
||||||
|
$width = imagesx($img);
|
||||||
|
$height = imagesy($img);
|
||||||
|
|
||||||
|
$canvas = imagecreatetruecolor($width, $height);
|
||||||
|
|
||||||
|
$hex = ltrim($bgColorHex, '#');
|
||||||
|
if (strlen($hex) === 3) {
|
||||||
|
$r = hexdec(substr($hex, 0, 1) . substr($hex, 0, 1));
|
||||||
|
$g = hexdec(substr($hex, 1, 1) . substr($hex, 1, 1));
|
||||||
|
$b = hexdec(substr($hex, 2, 1) . substr($hex, 2, 1));
|
||||||
|
} else {
|
||||||
|
$r = hexdec(substr($hex, 0, 2));
|
||||||
|
$g = hexdec(substr($hex, 2, 2));
|
||||||
|
$b = hexdec(substr($hex, 4, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
$bgColor = imagecolorallocate($canvas, $r, $g, $b);
|
||||||
|
imagefill($canvas, 0, 0, $bgColor);
|
||||||
|
imagealphablending($canvas, true);
|
||||||
|
|
||||||
|
imagecopy($canvas, $img, 0, 0, 0, 0, $width, $height);
|
||||||
|
|
||||||
|
$success = @imagejpeg($canvas, $targetJpgPath, $quality);
|
||||||
|
|
||||||
|
imagedestroy($img);
|
||||||
|
imagedestroy($canvas);
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function convertPngToWebpClean($sourcePngPath, $targetWebpPath, $quality = 80) {
|
||||||
|
if (!function_exists('imagewebp')) return false;
|
||||||
|
$img = @imagecreatefrompng($sourcePngPath);
|
||||||
|
if (!$img) return false;
|
||||||
|
|
||||||
|
if (function_exists('imagepalettetotruecolor') && !imageistruecolor($img)) {
|
||||||
|
imagepalettetotruecolor($img);
|
||||||
|
}
|
||||||
|
|
||||||
|
imagealphablending($img, false);
|
||||||
|
imagesavealpha($img, true);
|
||||||
|
|
||||||
|
$success = @imagewebp($img, $targetWebpPath, $quality);
|
||||||
|
imagedestroy($img);
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function normalizePngPalette($img) {
|
||||||
|
if ($img && function_exists('imagepalettetotruecolor') && !imageistruecolor($img)) {
|
||||||
|
imagepalettetotruecolor($img);
|
||||||
|
}
|
||||||
|
return $img;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function normalizeCmykToRgbJpeg($fullPath, $quality = 90) {
|
||||||
|
if (!is_file($fullPath)) return false;
|
||||||
|
|
||||||
|
if (extension_loaded('imagick')) {
|
||||||
|
try {
|
||||||
|
$img = new \Imagick($fullPath);
|
||||||
|
if ($img->getImageColorspace() == \Imagick::COLORSPACE_CMYK) {
|
||||||
|
$img->transformImageColorspace(\Imagick::COLORSPACE_SRGB);
|
||||||
|
$img->setImageFormat('jpeg');
|
||||||
|
$img->writeImage($fullPath);
|
||||||
|
$img->clear();
|
||||||
|
$img->destroy();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$img->clear();
|
||||||
|
$img->destroy();
|
||||||
|
} catch (\Exception $e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
$info = @getimagesize($fullPath);
|
||||||
|
if (isset($info['channels']) && $info['channels'] == 4) {
|
||||||
|
$img = @imagecreatefromjpeg($fullPath);
|
||||||
|
if ($img) {
|
||||||
|
$width = imagesx($img);
|
||||||
|
$height = imagesy($img);
|
||||||
|
$rgbCanvas = imagecreatetruecolor($width, $height);
|
||||||
|
for ($x = 0; $x < $width; $x++) {
|
||||||
|
for ($y = 0; $y < $height; $y++) {
|
||||||
|
$pixel = imagecolorat($img, $x, $y);
|
||||||
|
$c = ($pixel >> 16) & 0xFF;
|
||||||
|
$m = ($pixel >> 8) & 0xFF;
|
||||||
|
$y_val = $pixel & 0xFF;
|
||||||
|
|
||||||
|
$r = (int)(($c * $y_val) / 255);
|
||||||
|
$g = (int)(($m * $y_val) / 255);
|
||||||
|
$b = (int)($y_val);
|
||||||
|
|
||||||
|
$color = imagecolorallocate($rgbCanvas, min(255, max(0, $r)), min(255, max(0, $g)), min(255, max(0, $b)));
|
||||||
|
imagesetpixel($rgbCanvas, $x, $y, $color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@imagejpeg($rgbCanvas, $fullPath, $quality);
|
||||||
|
imagedestroy($img);
|
||||||
|
imagedestroy($rgbCanvas);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3300,8 +3300,10 @@ $(document).ready(function() {
|
||||||
<label class="col-sm-3 control-label"><?php echo $entry_wm_text_color; ?></label>
|
<label class="col-sm-3 control-label"><?php echo $entry_wm_text_color; ?></label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-addon" id="modal-wm-color-preview" style="background:#ffffff; width:36px;"> </span>
|
<span class="input-group-addon" style="padding: 3px 8px; background: #f8f9fa;">
|
||||||
<input type="text" id="wm-rule-text-color" class="form-control" placeholder="#ffffff" maxlength="7"/>
|
<input type="color" id="wm-rule-text-color-picker" value="#ffffff" style="width: 28px; height: 24px; border: none; padding: 0; cursor: pointer; background: transparent; vertical-align: middle;" />
|
||||||
|
</span>
|
||||||
|
<input type="text" id="wm-rule-text-color" class="form-control" placeholder="#ffffff" maxlength="7" value="#ffffff" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue