diff --git a/classes/file/FileHandler.class.php b/classes/file/FileHandler.class.php index ca04eacbc..47ce5b4fb 100644 --- a/classes/file/FileHandler.class.php +++ b/classes/file/FileHandler.class.php @@ -480,9 +480,10 @@ class FileHandler * @param string $target_type If $target_type is set (gif, jpg, png, bmp), result image will be saved as target type * @param string $thumbnail_type Thumbnail type(crop, ratio) * @param int $quality Compression ratio (0~9) + * @param int $rotate Rotation degrees (0~360) * @return bool TRUE: success, FALSE: failed */ - public static function createImageFile($source_file, $target_file, $resize_width = 0, $resize_height = 0, $target_type = '', $thumbnail_type = 'crop', $quality = 100) + public static function createImageFile($source_file, $target_file, $resize_width = 0, $resize_height = 0, $target_type = '', $thumbnail_type = 'crop', $quality = 100, $rotate = 0) { // check params if (($source_file = self::exists($source_file)) === FALSE) @@ -544,49 +545,6 @@ class FileHandler } $target_type = strtolower($target_type); - // if original image is larger than specified size to resize, calculate the ratio - $width_per = ($resize_width > 0 && $width >= $resize_width) ? $resize_width / $width : 1; - $height_per = ($resize_height > 0 && $height >= $resize_height) ? $resize_height / $height : 1; - - $per = NULL; - if($thumbnail_type == 'ratio') - { - $per = ($width_per > $height_per) ? $height_per : $width_per; - $resize_width = $width * $per; - $resize_height = $height * $per; - } - else - { - $per = ($width_per < $height_per) ? $height_per : $width_per; - } - - // create temporary image with target size - $thumb = NULL; - if(function_exists('imagecreateTRUEcolor')) - { - $thumb = imagecreateTRUEcolor($resize_width, $resize_height); - } - else if(function_exists('imagecreate')) - { - $thumb = imagecreate($resize_width, $resize_height); - } - - if(!$thumb) - { - return FALSE; - } - - if($target_type == 'png' && function_exists('imagecolorallocatealpha') && function_exists('imagesavealpha') && function_exists('imagealphablending')) - { - imagefill($thumb, 0, 0, imagecolorallocatealpha($thumb, 0, 0, 0, 127)); - imagesavealpha($thumb, TRUE); - imagealphablending($thumb, TRUE); - } - else - { - imagefilledrectangle($thumb, 0, 0, $resize_width - 1, $resize_height - 1, imagecolorallocate($thumb, 255, 255, 255)); - } - // create temporary image having original type $source = NULL; switch($type) @@ -636,27 +594,86 @@ class FileHandler return FALSE; } - // resize original image and put it into temporary image - $new_width = (int) ($width * $per); - $new_height = (int) ($height * $per); - - $x = 0; - $y = 0; - if($thumbnail_type == 'crop') + // Rotate image + if ($rotate) { - $x = (int) ($resize_width / 2 - $new_width / 2); - $y = (int) ($resize_height / 2 - $new_height / 2); + $source = imagerotate($source, $rotate, 0); + $width = imagesx($source); + $height = imagesy($source); } - if(function_exists('imagecopyresampled')) + // If resize not needed, skip thumbnail generation + if ($width == $resize_width && $height == $resize_height) { - imagecopyresampled($thumb, $source, $x, $y, 0, 0, $new_width, $new_height, $width, $height); + $thumb = &$source; } else { - imagecopyresized($thumb, $source, $x, $y, 0, 0, $new_width, $new_height, $width, $height); - } + // if original image is larger than specified size to resize, calculate the ratio + $width_per = ($resize_width > 0 && $width >= $resize_width) ? $resize_width / $width : 1; + $height_per = ($resize_height > 0 && $height >= $resize_height) ? $resize_height / $height : 1; + $per = NULL; + if($thumbnail_type == 'ratio') + { + $per = ($width_per > $height_per) ? $height_per : $width_per; + $resize_width = $width * $per; + $resize_height = $height * $per; + } + else + { + $per = ($width_per < $height_per) ? $height_per : $width_per; + } + + // create temporary image with target size + $thumb = NULL; + if(function_exists('imagecreateTRUEcolor')) + { + $thumb = imagecreateTRUEcolor($resize_width, $resize_height); + } + else if(function_exists('imagecreate')) + { + $thumb = imagecreate($resize_width, $resize_height); + } + + if(!$thumb) + { + return FALSE; + } + + if($target_type == 'png' && function_exists('imagecolorallocatealpha') && function_exists('imagesavealpha') && function_exists('imagealphablending')) + { + imagefill($thumb, 0, 0, imagecolorallocatealpha($thumb, 0, 0, 0, 127)); + imagesavealpha($thumb, TRUE); + imagealphablending($thumb, TRUE); + } + else + { + imagefilledrectangle($thumb, 0, 0, $resize_width - 1, $resize_height - 1, imagecolorallocate($thumb, 255, 255, 255)); + } + + // resize original image and put it into temporary image + $new_width = (int) ($width * $per); + $new_height = (int) ($height * $per); + + $x = 0; + $y = 0; + if($thumbnail_type == 'crop') + { + $x = (int) ($resize_width / 2 - $new_width / 2); + $y = (int) ($resize_height / 2 - $new_height / 2); + } + + if(function_exists('imagecopyresampled')) + { + imagecopyresampled($thumb, $source, $x, $y, 0, 0, $new_width, $new_height, $width, $height); + } + else + { + imagecopyresized($thumb, $source, $x, $y, 0, 0, $new_width, $new_height, $width, $height); + } + } + // create directory self::makeDir(dirname($target_file)); diff --git a/modules/file/file.admin.controller.php b/modules/file/file.admin.controller.php index 01851a752..981205d0c 100644 --- a/modules/file/file.admin.controller.php +++ b/modules/file/file.admin.controller.php @@ -73,6 +73,8 @@ class fileAdminController extends file $config->image_autoconv['bmp2jpg'] = Context::get('image_autoconv_bmp2jpg') === 'Y' ? true : false; $config->image_autoconv['webp2jpg'] = Context::get('image_autoconv_webp2jpg') === 'Y' ? true : false; $config->image_autoconv_quality = max(50, min(100, intval(Context::get('image_autoconv_quality')))); + $config->image_autorotate = Context::get('image_autorotate') === 'Y' ? true : false; + $config->image_autorotate_quality = max(50, min(100, intval(Context::get('image_autorotate_quality')))); // Check maximum file size if (PHP_INT_SIZE < 8) diff --git a/modules/file/file.controller.php b/modules/file/file.controller.php index 80ff3a83d..328543fc8 100644 --- a/modules/file/file.controller.php +++ b/modules/file/file.controller.php @@ -1051,11 +1051,41 @@ class fileController extends file // Check image type if($config->image_autoconv['bmp2jpg'] && function_exists('imagebmp') && $image_type === 6) { - $convert = array($image_width, $image_height, 'jpg', $config->image_autoconv_quality ?: 75); + $convert = array($image_width, $image_height, 'jpg', $config->image_autoconv_quality ?: 75, 0); } if($config->image_autoconv['webp2jpg'] && function_exists('imagewebp') && $image_type === 18) { - $convert = array($image_width, $image_height, 'jpg', $config->image_autoconv_quality ?: 75); + $convert = array($image_width, $image_height, 'jpg', $config->image_autoconv_quality ?: 75, 0); + } + + // Check image rotation + if($config->image_autorotate && function_exists('exif_read_data')) + { + $exif = @exif_read_data($file_info['tmp_name']); + if($exif && isset($exif['Orientation'])) + { + switch ($exif['Orientation']) + { + case 3: $rotate = 180; break; + case 6: $rotate = 270; break; + case 8: $rotate = 90; break; + default: $rotate = 0; + } + if ($rotate) + { + $convert = $convert ?: array($image_width, $image_height, $file_info['extension']); + if ($rotate == 90 || $rotate == 270) + { + $image_height = $convert[0]; + $image_width = $convert[1]; + $convert[0] = $image_width; + $convert[1] = $image_height; + } + $convert[3] = $config->image_autorotate_quality ?: 75; + $convert[4] = $rotate; + } + } + unset($exif); } // Check image size @@ -1108,7 +1138,8 @@ class fileController extends file $resize_height = $config->max_image_height; } $target_type = in_array($image_type, array(6, 8, 18)) ? 'jpg' : $file_info['extension']; - $convert = array(intval($resize_width), intval($resize_height), $target_type, $config->max_image_size_quality ?: 75); + $rotate = ($convert && $convert[4]) ? $convert[4] : 0; + $convert = array(intval($resize_width), intval($resize_height), $target_type, $config->max_image_size_quality ?: 75, $rotate); } } } @@ -1116,12 +1147,13 @@ class fileController extends file // Convert image if necessary if ($convert) { - $result = FileHandler::createImageFile($file_info['tmp_name'], $file_info['tmp_name'] . '.conv', $convert[0], $convert[1], $convert[2], 'crop', $convert[3]); + $result = FileHandler::createImageFile($file_info['tmp_name'], $file_info['tmp_name'] . '.conv', $convert[0], $convert[1], $convert[2], 'crop', $convert[3], $convert[4]); if ($result) { $file_info['name'] = preg_replace('/\.' . preg_quote($file_info['extension'], '/') . '$/i', '.' . $convert[2], $file_info['name']); $file_info['tmp_name'] = $file_info['tmp_name'] . '.conv'; $file_info['size'] = filesize($file_info['tmp_name']); + $file_info['extension'] = $convert[2]; $file_info['converted'] = true; } } diff --git a/modules/file/file.model.php b/modules/file/file.model.php index 3652cf18f..ad562ef84 100644 --- a/modules/file/file.model.php +++ b/modules/file/file.model.php @@ -195,6 +195,8 @@ class fileModel extends file $config->max_image_size_quality = $file_config->max_image_size_quality; $config->image_autoconv = $file_config->image_autoconv; $config->image_autoconv_quality = $file_config->image_autoconv_quality; + $config->image_autorotate = $file_config->image_autorotate; + $config->image_autorotate_quality = $file_config->image_autorotate_quality; $config->download_grant = $file_config->download_grant; $config->allow_outlink = $file_config->allow_outlink; $config->allow_outlink_site = $file_config->allow_outlink_site; @@ -215,6 +217,8 @@ class fileModel extends file if(!$config->max_image_size_quality) $config->max_image_size_quality = $file_module_config->max_image_size_quality; if(!$config->image_autoconv) $config->image_autoconv = $file_module_config->image_autoconv; if(!$config->image_autoconv_quality) $config->image_autoconv_quality = $file_module_config->image_autoconv_quality; + if(!$config->image_autorotate) $config->image_autorotate = $file_module_config->image_autorotate; + if(!$config->image_autorotate_quality) $config->image_autorotate_quality = $file_module_config->image_autorotate_quality; // Default setting if not exists if(!$config->allowed_filesize) $config->allowed_filesize = '2'; @@ -226,6 +230,7 @@ class fileModel extends file if(!$config->max_image_size_quality) $config->max_image_size_quality = 75; if(!$config->image_autoconv) $config->image_autoconv = array(); if(!$config->image_autoconv_quality) $config->image_autoconv_quality = 75; + if(!$config->image_autorotate_quality) $config->image_autorotate_quality = 75; return $config; } diff --git a/modules/file/lang/en.php b/modules/file/lang/en.php index 0fdc23d03..0eba73a2d 100644 --- a/modules/file/lang/en.php +++ b/modules/file/lang/en.php @@ -25,6 +25,7 @@ $lang->image_resize_quality = 'Quality'; $lang->image_autoconv = 'Auto-Convert Image'; $lang->image_autoconv_bmp2jpg = 'BMP → JPG'; $lang->image_autoconv_webp2jpg = 'WebP → JPG'; +$lang->image_autorotate = 'Auto-Rotate Image'; $lang->inline_download_format = 'Open in current window'; $lang->inline_download_image = 'Image'; $lang->inline_download_audio = 'Audio'; @@ -44,6 +45,7 @@ $lang->about_allowed_size_limits = 'The file size will be limited to the value s $lang->about_allowed_filetypes = 'To allow an extension, use "*.[extention]". To allow multiple extensions, use ";" between each extension. ex) *.* or *.jpg;*.gif; '; $lang->about_max_image_size = 'You can limit the maximum width and/or height of uploaded images.
This limit does not apply to files uploaded by the administrator.'; $lang->about_image_autoconv = 'Automatically convert types of images that often cause trouble or waste disk space into other types.
This also works for WebP images that incorrectly have the JPG extension.
If enabled, this feature also applies to images uploaded by the administrator.'; +$lang->about_image_autorotate = 'Automatically correct images that are rotated by mobile devices.
If enabled, this feature also applies to images uploaded by the administrator.'; $lang->cmd_delete_checked_file = 'Delete Selected Item(s)'; $lang->cmd_move_to_document = 'Move to Document'; $lang->cmd_download = 'Download'; diff --git a/modules/file/lang/ko.php b/modules/file/lang/ko.php index d24c371e4..dbe2b31f0 100644 --- a/modules/file/lang/ko.php +++ b/modules/file/lang/ko.php @@ -25,6 +25,7 @@ $lang->image_resize_quality = '화질'; $lang->image_autoconv = '이미지 자동 변환'; $lang->image_autoconv_bmp2jpg = 'BMP → JPG'; $lang->image_autoconv_webp2jpg = 'WebP → JPG'; +$lang->image_autorotate = '이미지 자동 회전'; $lang->inline_download_format = '다운로드시 현재 창 사용'; $lang->inline_download_image = '이미지'; $lang->inline_download_audio = '오디오'; @@ -44,6 +45,7 @@ $lang->about_allowed_size_limits = 'IE9 이하, 구버전 안드로이드 등에 $lang->about_allowed_filetypes = '"*.확장자"로 지정할 수 있고 ";" 으로 여러 개 지정이 가능합니다. 예) *.* or *.jpg;*.gif;'; $lang->about_max_image_size = '이미지 파일의 가로, 세로, 또는 가로세로 크기를 모두 제한할 수 있습니다.
관리자가 업로드한 파일에는 적용되지 않습니다.'; $lang->about_image_autoconv = '종종 문제를 일으키거나 용량을 낭비하는 이미지 타입을 다른 타입으로 자동 변환합니다.
WebP 이미지에 JPG 확장자가 잘못 부여된 경우에도 변환할 수 있습니다.
관리자가 업로드한 파일에도 적용됩니다.'; +$lang->about_image_autorotate = '모바일 기기 등에서 잘못 회전된 이미지를 바로잡습니다.
관리자가 업로드한 파일에도 적용됩니다.'; $lang->cmd_delete_checked_file = '선택항목 삭제'; $lang->cmd_move_to_document = '문서로 이동'; $lang->cmd_download = '다운로드'; diff --git a/modules/file/tpl/upload_config.html b/modules/file/tpl/upload_config.html index c2123462b..fcb1d4d7e 100644 --- a/modules/file/tpl/upload_config.html +++ b/modules/file/tpl/upload_config.html @@ -61,6 +61,26 @@

{$lang->about_image_autoconv}

+
+ +
+ + + +

{$lang->about_image_autorotate}

+
+