feat: 图片上传水印处理
This commit is contained in:
@@ -141,6 +141,44 @@ class SiteConfig
|
||||
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()
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ use app\admin\model\v1\SysImageUploadRecordModel;
|
||||
use app\admin\model\v1\SysVideoUploadRecordModel;
|
||||
use app\admin\model\v1\SysAttachmentUploadRecordModel;
|
||||
use Intervention\Image\ImageManager;
|
||||
use Intervention\Image\Typography\FontFactory;
|
||||
use think\facade\Filesystem;
|
||||
|
||||
/**
|
||||
@@ -44,9 +45,68 @@ class Upload
|
||||
$image_model = SysImageUploadRecordModel::md5($filemd5)->find();
|
||||
if (is_null($image_model)) {
|
||||
$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);
|
||||
|
||||
// 水印
|
||||
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);
|
||||
$idx = strrpos($filename, '.');
|
||||
$thumb_filename = mb_substr($filename, 0, $idx) . '_thumb.' . mb_substr($filename, $idx + 1);
|
||||
@@ -79,6 +139,85 @@ class Upload
|
||||
|
||||
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