feat: 图片上传水印处理
This commit is contained in:
@@ -141,6 +141,44 @@ class SiteConfig
|
|||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据分组获取配置
|
||||||
|
public function getByGroupUniqueLabel($unique_label)
|
||||||
|
{
|
||||||
|
$configs = SysConfigModel::alias('c')
|
||||||
|
->field([
|
||||||
|
'c.id',
|
||||||
|
'c.title',
|
||||||
|
'c.name',
|
||||||
|
'c.value',
|
||||||
|
])
|
||||||
|
->join(SysConfigGroupModel::getTable(). ' g', 'g.id = c.group_id')
|
||||||
|
->where('g.language_id', '=', request()->lang_id)
|
||||||
|
->where('g.unique_label', '=', $unique_label)
|
||||||
|
->where('g.status', '=', 1)
|
||||||
|
->order(['c.sort' => 'asc', 'c.id' => 'desc'])
|
||||||
|
->select()
|
||||||
|
->each(function ($item) {
|
||||||
|
// 修改字段为null的输出为空字符串
|
||||||
|
$keys = array_keys($item->toArray());
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
if (is_null($item[$key])) {
|
||||||
|
$item[$key] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $item;
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
if (!empty($configs)) {
|
||||||
|
$configs_map = [];
|
||||||
|
foreach ($configs as $cfg) {
|
||||||
|
$configs_map[$cfg['name']] = $cfg;
|
||||||
|
}
|
||||||
|
return $configs_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
// 更新配置
|
// 更新配置
|
||||||
public function update()
|
public function update()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use app\admin\model\v1\SysImageUploadRecordModel;
|
|||||||
use app\admin\model\v1\SysVideoUploadRecordModel;
|
use app\admin\model\v1\SysVideoUploadRecordModel;
|
||||||
use app\admin\model\v1\SysAttachmentUploadRecordModel;
|
use app\admin\model\v1\SysAttachmentUploadRecordModel;
|
||||||
use Intervention\Image\ImageManager;
|
use Intervention\Image\ImageManager;
|
||||||
|
use Intervention\Image\Typography\FontFactory;
|
||||||
use think\facade\Filesystem;
|
use think\facade\Filesystem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,9 +45,68 @@ class Upload
|
|||||||
$image_model = SysImageUploadRecordModel::md5($filemd5)->find();
|
$image_model = SysImageUploadRecordModel::md5($filemd5)->find();
|
||||||
if (is_null($image_model)) {
|
if (is_null($image_model)) {
|
||||||
$filename = Filesystem::disk('image')->putFile($param['module'], $file);
|
$filename = Filesystem::disk('image')->putFile($param['module'], $file);
|
||||||
// 生成缩略图
|
// 处理图片
|
||||||
$image_manager = new ImageManager(new \Intervention\Image\Drivers\Imagick\Driver());
|
$image_manager = ImageManager::imagick();
|
||||||
$image = $image_manager->read('.' . $storage . '/' . $filename);
|
$image = $image_manager->read('.' . $storage . '/' . $filename);
|
||||||
|
|
||||||
|
// 水印
|
||||||
|
list($enabled, $type, $text_options, $image_options) = $this->getWatermarkOptions();
|
||||||
|
if ($enabled) {
|
||||||
|
// 图片水印
|
||||||
|
if ($type == 'IMAGE' && $image_options['image'] != '') {
|
||||||
|
// 读取水印图片
|
||||||
|
$watermark_image = $image_manager->read($image_options['image']);
|
||||||
|
// 缩放水印图片
|
||||||
|
$watermark_image->scale($image_options['width'], $image_options['height']);
|
||||||
|
// 绘制水印图片
|
||||||
|
$image->place(
|
||||||
|
$watermark_image,
|
||||||
|
$image_options['position'],
|
||||||
|
$image_options['offset_x'],
|
||||||
|
$image_options['offset_y'],
|
||||||
|
$image_options['opacity']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 文字水印
|
||||||
|
else if ($type == 'TEXT' && $text_options['txt'] != '') {
|
||||||
|
// 原图宽度
|
||||||
|
$origin_width = $image->width();
|
||||||
|
// 原图高度
|
||||||
|
$origin_height = $image->height();
|
||||||
|
|
||||||
|
$font_factory = new FontFactory(function(FontFactory $font) use($text_options) {
|
||||||
|
// 设置字体
|
||||||
|
$font->filename($text_options['font']);
|
||||||
|
// 设置字体大小
|
||||||
|
$font->size($text_options['size']);
|
||||||
|
// 设置字体颜色及透明度
|
||||||
|
$opacity = dechex((int)ceil(255 * ($text_options['opacity'] / 100)));
|
||||||
|
$font->color($text_options['color'] . $opacity);
|
||||||
|
});
|
||||||
|
// 文字尺寸
|
||||||
|
$font_rect = $image->driver()->fontProcessor()->boxSize($text_options['txt'], $font_factory());
|
||||||
|
// 计算偏移量
|
||||||
|
list($offset_x, $offset_y) = $this->scaleTxtOffsetXYByPosition(
|
||||||
|
$text_options['position'],
|
||||||
|
$text_options['offset_x'],
|
||||||
|
$text_options['offset_y'],
|
||||||
|
$origin_width,
|
||||||
|
$origin_height,
|
||||||
|
$font_rect->width(),
|
||||||
|
$font_rect->height()
|
||||||
|
);
|
||||||
|
// 绘制文字
|
||||||
|
$image->text(
|
||||||
|
$text_options['txt'],
|
||||||
|
$offset_x,
|
||||||
|
$offset_y,
|
||||||
|
$font_factory()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$image->save('.'. $storage. '/'. $filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缩略图
|
||||||
$image->scale(200, 200);
|
$image->scale(200, 200);
|
||||||
$idx = strrpos($filename, '.');
|
$idx = strrpos($filename, '.');
|
||||||
$thumb_filename = mb_substr($filename, 0, $idx) . '_thumb.' . mb_substr($filename, $idx + 1);
|
$thumb_filename = mb_substr($filename, 0, $idx) . '_thumb.' . mb_substr($filename, $idx + 1);
|
||||||
@@ -79,6 +139,85 @@ class Upload
|
|||||||
|
|
||||||
return error('上传失败');
|
return error('上传失败');
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 获取水印配置
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getWatermarkOptions(): array
|
||||||
|
{
|
||||||
|
$config_model = new \app\admin\controller\v1\SiteConfig;
|
||||||
|
$watermark_config = $config_model->getByGroupUniqueLabel('watermark');
|
||||||
|
return [
|
||||||
|
'enalbed' => data_get($watermark_config, 'watermark_enabled.value', 0) == 1,
|
||||||
|
'type' => data_get($watermark_config, 'watermark_type.value', ''),
|
||||||
|
'text_options' => [
|
||||||
|
'txt' => data_get($watermark_config, 'watermark_text_value.value', ''),
|
||||||
|
'font' => data_get($watermark_config, 'watermark_font_family.value', ''),
|
||||||
|
'size' => (float)data_get($watermark_config, 'watermark_text_size.value', 12),
|
||||||
|
'color' => data_get($watermark_config, 'watermark_text_color.value', '#000000'),
|
||||||
|
'position' => data_get($watermark_config, 'watermark_position.value', 'top-left'),
|
||||||
|
'offset_x' => (int)data_get($watermark_config, 'watermark_offset_x.value', 0),
|
||||||
|
'offset_y' => (int)data_get($watermark_config, 'watermark_offset_y.value', 0),
|
||||||
|
'opacity' => (int)data_get($watermark_config, 'watermark_opacity.value', 100),
|
||||||
|
],
|
||||||
|
'image_options' => [
|
||||||
|
'image' => data_get($watermark_config, 'watermark_image_value.value', ''),
|
||||||
|
'width' => data_get($watermark_config, 'watermark_image_width.value', null),
|
||||||
|
'height' => data_get($watermark_config, 'watermark_image_height.value', null),
|
||||||
|
'position' => data_get($watermark_config, 'watermark_position.value', 'top-left'),
|
||||||
|
'offset_x' => (int)data_get($watermark_config, 'watermark_offset_x.value', 0),
|
||||||
|
'offset_y' => (int)data_get($watermark_config, 'watermark_offset_y.value', 0),
|
||||||
|
'opacity' => (int)data_get($watermark_config, 'watermark_opacity.value', 100),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 计算文体水印偏移量
|
||||||
|
*
|
||||||
|
* @param string $position
|
||||||
|
* @param integer $offset_x
|
||||||
|
* @param integer $offset_y
|
||||||
|
* @param integer $image_width
|
||||||
|
* @param integer $image_height
|
||||||
|
* @param integer $txt_width
|
||||||
|
* @param integer $txt_height
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function scaleTxtOffsetXYByPosition(string $position, int $offset_x, int $offset_y, int $image_width, int $image_height, int $txt_width, int $txt_height)
|
||||||
|
{
|
||||||
|
switch ($position) {
|
||||||
|
case 'top-left':
|
||||||
|
// top-left:左上角
|
||||||
|
return [$offset_x, $offset_y];
|
||||||
|
case 'top-right':
|
||||||
|
// top-right:右上角
|
||||||
|
return [(int)($image_width-$txt_width-$offset_x), $offset_y];
|
||||||
|
case 'top':
|
||||||
|
// top:上 - 水平居中
|
||||||
|
return [(int)(($image_width-$txt_width+$offset_x)/2), $offset_y];
|
||||||
|
case 'left':
|
||||||
|
// left:左 - 垂直居中
|
||||||
|
return [$offset_x, (int)(($image_height-$txt_height)/2+$offset_y)];
|
||||||
|
case 'center':
|
||||||
|
// center:水平垂直居中
|
||||||
|
return [(int)(($image_width-$txt_width)/2+$offset_x), (int)(($image_height-$txt_height)/2+$offset_y)];
|
||||||
|
case 'right':
|
||||||
|
// right:右 - 垂直居中
|
||||||
|
return [(int)($image_width-$txt_width-$offset_x), (int)(($image_height-$txt_height)/2+$offset_y)];
|
||||||
|
case'bottom':
|
||||||
|
// bottom:下 - 水平居中
|
||||||
|
return [(int)(($image_width-$txt_width+$offset_x)/2), (int)($image_height-$txt_height-$offset_y)];
|
||||||
|
case'bottom-left':
|
||||||
|
// bottom-left:左下角
|
||||||
|
return [$offset_x, (int)($image_height-$txt_height-$offset_y)];
|
||||||
|
case'bottom-right':
|
||||||
|
// bottom-right:右下角
|
||||||
|
return [(int)($image_width-$txt_width-$offset_x), (int)($image_height-$txt_height-$offset_y)];
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException('Invalid position');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传视频
|
* 上传视频
|
||||||
|
|||||||
Reference in New Issue
Block a user