Initial commit
Some checks failed
定时更新GitHub源插件 / 自动更新GitHub插件 (push) Has been cancelled

This commit is contained in:
chorblack
2026-03-07 11:19:25 +08:00
commit e75f275ef4
4484 changed files with 645480 additions and 0 deletions

104
Watermark/Action.php Normal file
View File

@@ -0,0 +1,104 @@
<?php
/**
* Watermark Plugin
*
* @copyright Copyright (c) 2013 DEFE (http://defe.me)
* @license GNU General Public License 2.0
*
*/
class Watermark_Action extends Typecho_Widget implements Widget_Interface_Do
{
public function mark($img){
$options = $this->widget('Widget_Options');
$cfg = $options->plugin('Watermark');
$img1 = self::lujin( __TYPECHO_ROOT_DIR__ . base64_decode($img));
$dir='.'.__TYPECHO_PLUGIN_DIR__ . '/Watermark/';
$ck_p = 0;
$ck_t = 0;
if(in_array('pic',$cfg->vm_type) && file_exists($dir . $cfg->vm_pic)) $ck_p = 1;
if(in_array('text',$cfg->vm_type) && file_exists($dir . $cfg->vm_font)) $ck_t = 1;
$pos_p = $cfg->vm_pos_pic;
$pos_t = $cfg->vm_pos_text;
$font = $dir . $cfg->vm_font;
$text = $cfg->vm_text;
$size = $cfg->vm_size;
$color = $cfg->vm_color;
$mic_x = $cfg->vm_m_x;
$mic_y = $cfg->vm_m_y;
$width = $cfg->vm_width;
$wmpic = $cfg->vm_pic?$cfg->vm_pic:'WM.png';
$alpha = $cfg->vm_alpha;
$file = false;
if(file_exists($img1)){
require_once($dir.'class.php');
$wm = new WaterMark();
$wm->setImSrc($img1,$width); // 设置背景图
$wm->setImWater($dir.$wmpic); // 设置水印图
$wm->setFont($font, $text, $size, $color); // 设置水印文字相关(字体库、文本、字体大小、颜色)
if( isset($cfg->vm_cache) && 'cache' == $cfg->vm_cache){
$file = base64_decode($img);
$ext = pathinfo($file, PATHINFO_EXTENSION);
$dir_cache = __TYPECHO_ROOT_DIR__ . '/usr/img';
if(!is_dir($dir_cache)) @mkdir($dir_cache, 0777);//检测缓存目录是否存在,自动创建
$file = './usr/img/'.md5($file).'.'.$ext;
}
$wm->mark($ck_p, $pos_p, $ck_t, $pos_t, $mic_x, $mic_y, $alpha, $file);
}else{
$this->widget('Widget_Archive@404', 'type=404')->render();
}
}
/**
* 清除水印图片缓存
* @return boolean
*/
public function clear(){
$this->widget('Widget_User')->pass('administrator');
$dir_cache = __TYPECHO_ROOT_DIR__. '/usr/img/';
if (is_writable($dir_cache)){
chdir($dir_cache);
$dh=opendir('.');
$num = 0;
while(false !== ($et=readdir($dh))){
if(is_file($et)){
if(!@unlink($et)){
return false;
echo "缓存文件 {$et} 未能删除,请检查目录权限";
break;
}
echo "清除文件:{$et} <br>";
$num++;
}
}
closedir($dh);
echo "共清除 {$num} 个缓存文件<br>";
chdir('..');
if(@rmdir('img')) echo '缓存文件目录已删除';
}
}
/**
* 合并重复路径
* @param string $uri
* @return string
*/
public static function lujin($uri){
$uri = str_replace("\\","/",$uri);
$a = explode('/', $uri);
$b = array_unique($a);
return implode('/', $b);
}
public function action(){
$this->on($this->request->is('mark'))->mark($this->request->mark);
$this->on($this->request->is('clear'))->clear();
}
}
?>

Binary file not shown.

215
Watermark/Plugin.php Normal file
View File

@@ -0,0 +1,215 @@
<?php
/**
* 生成图片水印
*
* @package Watermark
* @author DEFE
* @version 1.2.0
* @link http://defe.me
*/
class Watermark_Plugin implements Typecho_Plugin_Interface
{
/**
* 激活插件方法,如果激活失败,直接抛出异常
*
* @access public
* @return void
* @throws Typecho_Plugin_Exception
*/
public static function activate()
{
if(!function_exists('gd_info')){
throw new Typecho_Plugin_Exception(_t('对不起, 您的主机没有PHP中开启GD库支持'));
}
Typecho_Plugin::factory('Widget_Abstract_Contents')->filter = array('Watermark_Plugin', 'parse');
Helper::addAction('Watermark', 'Watermark_Action');
$dir = __TYPECHO_ROOT_DIR__ . '/usr/img';
if((is_dir($dir)|| @mkdir($dir, 0777)) && is_writable($dir)){
return _t('插件已经激活,请正确设置插件!');
}else {
return _t('usr目录权限限制无法使用缓存功能');
}
}
/**
* 禁用插件方法,如果禁用失败,直接抛出异常
*
* @static
* @access public
* @return void
* @throws Typecho_Plugin_Exception
*/
public static function deactivate(){
Helper::removeAction('Watermark');
}
/**
* 获取插件配置面板
*
* @access public
* @param Typecho_Widget_Helper_Form $form 配置面板
* @return void
*/
public static function config(Typecho_Widget_Helper_Form $form){
$vm_type= new Typecho_Widget_Helper_Form_Element_Checkbox('vm_type',
array( 'pic' => '图片',
'text' => '文字'),
array('pic'), '水印类型');
$form->addInput($vm_type);
$vm_pos_pic= new Typecho_Widget_Helper_Form_Element_Select('vm_pos_pic',array('随机','顶端左侧',
'顶端中间','顶端右侧','中部左侧','正中','中部右侧','底部左侧','底部中间','底部右侧'),9,_t('水印图片位置'));
$form->addInput($vm_pos_pic);
$vm_pos_text= new Typecho_Widget_Helper_Form_Element_Select('vm_pos_text',array('随机','顶端左侧',
'顶端中间','顶端右侧','中部左侧','正中','中部右侧','底部左侧','底部中间','底部右侧'),9,_t('水印文字位置'));
$form->addInput($vm_pos_text);
$file_list = scandir(dirname(__FILE__));
if($file_list){
$images = array();
$fonts = array();
foreach ($file_list as $file){
$ext = '';
$part = explode('.', $file);
if (($length = count($part)) > 1) {
$ext = strtolower($part[$length - 1]);
}
if('ttf' == $ext || 'ttc' == $ext) $fonts[]=$file;
if(in_array($ext, array('png','gif','jpg'))) $images[] = $file;
}
if(count($images)>0){
$img_msg = "可用图片: <span>". implode('</span><span>', $images)."</span>请复制图片文件名到上方文本框中";
}else{
$img_msg = "目录中没有图片文件,无法使用图片水印功能";
}
if(count($fonts)>0){
$font_msg = "可用字体: <span>". implode('</span><span>', $fonts)."</span>请复制字体文件名到输入框中";
}else{
$font_msg = "插件目录下没有字体文件,无法使用文字水印";
}
}else{
$img_msg = "插件目录下的图片文件名,注意大小写。";
$font_msg = "本插件目录下的字体文件。";
}
$vm_pic = new Typecho_Widget_Helper_Form_Element_Text('vm_pic', NULL, 'WM.png',
_t('水印图片'),_t($img_msg));
$vm_pic->input->setAttribute('class', 'mini');
$form->addInput($vm_pic);
$vm_text = new Typecho_Widget_Helper_Form_Element_Text('vm_text',null,"Typecho)))",
_t('水印文字'));
$form->addInput($vm_text);
$vm_font = new Typecho_Widget_Helper_Form_Element_Text('vm_font', NULL, 'lh.ttf',
_t('文字字体'),_t($font_msg));
$vm_font->input->setAttribute('class', 'mini');
$form->addInput($vm_font);
$vm_size = new Typecho_Widget_Helper_Form_Element_Text('vm_size', NULL, '16',
_t('文字大小'));
$vm_size->input->setAttribute('class', 'mini');
$form->addInput($vm_size);
$vm_color = new Typecho_Widget_Helper_Form_Element_Text('vm_color', NULL, '255,0,0',
_t('文字颜色'), _t('格式255,255,255 或 #FF0000'));
$vm_color->input->setAttribute('class', 'mini');
$form->addInput($vm_color);
$vm_m_x = new Typecho_Widget_Helper_Form_Element_Text('vm_m_x', NULL, '0',
_t('水平微调'), _t('调节文字的水平位置,输入整数,可以为负'));
$vm_m_x->input->setAttribute('class', 'mini');
$form->addInput($vm_m_x->addRule('isInteger', _t('必须是纯数字')));
$vm_m_y = new Typecho_Widget_Helper_Form_Element_Text('vm_m_y', NULL, '0',
_t('竖直微调'), _t('调节文字的竖直位置,输入整数,可以为负'));
$vm_m_y->input->setAttribute('class', 'mini');
$form->addInput($vm_m_y->addRule('isInteger', _t('必须是纯数字')));
$vm_width = new Typecho_Widget_Helper_Form_Element_Text('vm_width', NULL, '0',
_t('调整图片宽度'), _t('为了使水印效果一致,可以限制图片的宽度,建议和缓存搭配使用。设为 0 则不调整。'));
$vm_width->input->setAttribute('class', 'mini');
$form->addInput($vm_width->addRule('isInteger', _t('必须是纯数字')));
$vm_alpha = new Typecho_Widget_Helper_Form_Element_Text('vm_alpha', NULL, '0',
_t('图片透明度'), _t('取0-100之间的整数0为不透明100为全透明。'));
$vm_alpha->input->setAttribute('class', 'mini');
$form->addInput($vm_alpha->addRule('isInteger', _t('必须是纯数字')));
$dir = __TYPECHO_ROOT_DIR__ . '/usr/img';
if(is_dir($dir) && is_writable($dir)){
$url = Typecho_Widget::widget('Widget_Options')->index . "/action/Watermark?clear";
$msg = '清除缓存文件可以 <a href="'.$url.'" target="_blank"> 点击这里 </a> 执行清空缓存功能。';
}else{
$msg = '缓存已清空,或是未用缓存(如果启用缓存后每次设置均出现此提示,请检查目录权限)';
}
$vm_cache= new Typecho_Widget_Helper_Form_Element_Radio('vm_cache',
array( 'cache' => '使用缓存',
'nocache' => '不使用缓存'),
'nocache', '使用缓存',_t($msg));
$form->addInput($vm_cache);
}
/**
* 个人用户的配置面板
*
* @access public
* @param Typecho_Widget_Helper_Form $form
* @return void
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form){}
/**
* 解析内容
*
* @access public
* @param Typecho_Widget_Helper_Form $form
* @return void
*/
public static function parse($value_o)
{
if('index.php' === basename($_SERVER['SCRIPT_NAME'])){
$options = Typecho_Widget::widget('Widget_Options');
$cache_ab = $options->plugin('Watermark')->vm_cache?$options->plugin('Watermark')->vm_cache:FALSE;
$value = $value_o['text'];
if($value_o['isMarkdown']){
$regex = "/\[\d{1,}\]:\s(.*?.(gif|jpg|png))/";
}else{
$regex = "/<img.*?src=\"(.*?)\".*?[\/]?>/";
}
preg_match_all($regex, $value, $matches);
$count = count($matches[0]);
for($i = 0;$i < $count;$i++) {
$url = $matches[1][$i];
$m = parse_url($url);
$ext = strtolower(pathinfo($m['path'], PATHINFO_EXTENSION));
if( $ext=='gif' && self::IsAnimatedGif( Watermark_Action::lujin(__TYPECHO_ROOT_DIR__ .$m['path']))){ continue;}//避开动态gif
$cache_file = 'usr/img/'.md5($m['path']).'.'.$ext;
if('cache' == $cache_ab && file_exists('./'.$cache_file)){
$mUrl = $options->siteUrl . $cache_file;
}else{
$mUrl = $options->index.'/action/Watermark?mark='.base64_encode($m['path']);
}
$url = str_replace($url, $mUrl, $matches[0][$i]);
$value = str_replace($matches[0][$i], $url, $value);
}
$value_o['text'] = $value;
}
return $value_o;
}
public static function IsAnimatedGif($filename){
$fp = fopen($filename, 'rb');
$size = filesize($filename)>1024?1024:filesize($filename);
$filecontent = fread($fp, $size);
fclose($fp);
return strpos($filecontent,chr(0x21).chr(0xff).chr(0x0b).'NETSCAPE2.0') === FALSE?0:1;
}
}

7
Watermark/README.md Normal file
View File

@@ -0,0 +1,7 @@
### 图片自动添加水印插件Watermark v1.2.0
实现指定图片或文本作为水印显示在附件插图上,可设置方位、大小、字体等,支持缓存。
> 更新字体修正注释。
###### 更多详见作者博客http://defe.me/prg/431.html

BIN
Watermark/WM.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

338
Watermark/class.php Normal file
View File

@@ -0,0 +1,338 @@
<?php
class WaterMark{
private $im_src; // 背景图文件
private $im_src_width; // 背景图宽度
private $im_src_height; // 背景图高度
private $src_im; // 由背景图创建的新图
private $im_water; // 水印图文件
private $im_water_width; // 水印图宽度
private $im_water_height; // 水印图高度
private $water_im; // 由水印图创建的新图
private $font; // 字体库
private $font_text; // 文本
private $font_size; // 字体大小
private $font_color; // 字体颜色
private $type; //类型
private $mime;
function setImSrc($img,$width = 0){
$this->im_src = $img;
//读取背景图片文件
$srcInfo = @getimagesize($this->im_src);
$this->im_src_width = $srcInfo[0];
$this->im_src_height = $srcInfo[1];
$this->type = $srcInfo[2];
$this->mime = $srcInfo['mime'];
//取得背景图片
$this->src_im = $this->getType($this->im_src, $srcInfo[2]);
if($width){
$this->resize($width);
}
}
function setImWater($img){
$this->im_water = $img;
//读取水印图片文件
$waterInfo = @getimagesize($this->im_water);
$this->im_water_width = $waterInfo[0];
$this->im_water_height = $waterInfo[1];
//取得水印图片
$this->water_im = $this->getType($this->im_water, $waterInfo[2]);
}
function setFont($font, $text, $size, $color){
$this->font = $font;
$this->font_text = $text;
$this->font_size = $size;
//水印文字颜色('255,255,255'
$this->font_color = $color;
}
/**
* 根据文件或URL创建一个新图象
* @param $img
* @param $type
* @return resource
*/
function getType($img, $type){
switch($type){
case 1:
$im = imagecreatefromgif($img);
break;
case 2:
$exif = exif_read_data($img, 'EXIF');
$im = imagecreatefromjpeg($img);
if($exif!=false){
switch($exif['Orientation']) {
case 8:
$im = imagerotate($im,90,0);
break;
case 3:
$im = imagerotate($im,180,0);
break;
case 6:
$im = imagerotate($im,-90,0);
break;
}
}
break;
case 3:
$im = imagecreatefrompng($img);
imagesavealpha($im, true);
break;
default:break;
}
return $im;
}
/**
* 根据位置及水印宽高获取打印的x/y坐标
* @param $pos
* @param $w
* @param $h
*/
function getPos($pos, $w, $h)
{
switch($pos){
case 0://随机
$posX = rand(0, ($this->im_src_width - $w));
$posY = rand(0, ($this->im_src_height - $h));
break;
case 1://1为顶端居左
$posX = 0;
$posY = 0;
break;
case 2://2为顶端居中
$posX = ceil($this->im_src_width - $w) / 2;
$posY = 0;
break;
case 3://3为顶端居右
$posX = $this->im_src_width - $w;
$posY = 0;
break;
case 4://4为中部居左
$posX = 0;
$posY = ceil($this->im_src_height - $h) / 2;
break;
case 5://5为中部居中
$posX = ceil($this->im_src_width - $w) / 2;
$posY = ceil($this->im_src_height - $h) / 2;
break;
case 6://6为中部居右
$posX = $this->im_src_width - $w;
$posY = ceil($this->im_src_height - $h) / 2;
break;
case 7://7为底端居左
$posX = 0;
$posY = $this->im_src_height - $h;
break;
case 8://8为底端居中
$posX = ceil($this->im_src_width - $w) / 2;
$posY = $this->im_src_height - $h;
break;
case 9://9为底端居右
$posX = $this->im_src_width - $w;
$posY = $this->im_src_height - $h;
break;
default://随机
$posX = rand(0,($this->im_src_width - $w));
$posY = rand(0,($this->im_src_height - $h));
break;
}
return array($posX, $posY);
}
/**
* 校验尺寸
* @param $w
* @param $h
* @return boolean
*/
function check_range($w, $h){
if( ($this->im_src_width < $w) || ($this->im_src_height < $h) ){
return false;
}
return true;
}
/**
* 打水印操作
* @param $is_image 是1否0水印图片
* @param $image_pos 水印图片位置0~9
* @param $is_text 是1否0水印文字
* @param $text_pos 水印文字位置0~9
*/
function mark($is_image=0, $image_pos=0, $is_text=0, $text_pos=0, $mic_x=0, $mic_y=0, $alpha=0, $save=FALSE){
// 水印图片情况
if ($is_image)
{
// 校验图片大小,太小无法加水印直接返回
if (!$this->check_range($this->im_water_width, $this->im_water_height)){
$this->show();
$this->clean();
return;
}
$posArr = $this->getPos($image_pos, $this->im_water_width, $this->im_water_height);
$posX = $posArr[0];
$posY = $posArr[1];
// 拷贝水印到目标文件
if($alpha){
$this->imagecopymerge_alpha($this->src_im, $this->water_im, $posX, $posY, 0, 0, $this->im_water_width, $this->im_water_height, $alpha);
}else{
imagecopy($this->src_im, $this->water_im, $posX, $posY, 0, 0, $this->im_water_width, $this->im_water_height);
}
}
// 水印文字情况
if ($is_text){
//取得此字体的文本的范围
$temp = imagettfbbox($this->font_size, 0, $this->font, $this->font_text);
$w = $temp[2] - $temp[0];
$h = $temp[1] - $temp[7];
unset($temp);
// 校验图片大小,太小无法加水印直接返回
if (!$this->check_range($w, $h)){
$this->show();
$this->clean();
return;
}
$posArr = $this->getPos($text_pos, $w, $h);
$posX = $posArr[0]+$mic_x;
$posY = $posArr[1]+$mic_y;
// 打印文本
$rgb = explode(',', $this->font_color);
if (count($rgb) != 3){
$rgb = $this->hex2rgb($this->font_color);
file_put_contents('log.txt',$this->font_color);
$color = imagecolorallocate($this->src_im, $rgb['r'], $rgb['g'], $rgb['b']);
}else{
$color = imagecolorallocate($this->src_im, $rgb[0], $rgb[1], $rgb[2]);
}
imagettftext($this->src_im, $this->font_size, 0, $posX, $posY, $color, $this->font, $this->font_text);
}
// 输出
$this->show();
if($save){
$this->save($save);
}
// 清理
$this->clean();
}
/**
* 输出图像
*/
function show() {
ob_clean();
header("Content-type: {$this->mime}; charset=UTF-8");
switch ($this->type){
case 1:
imagegif($this->src_im);
break;
case 2:
imagejpeg($this->src_im);
break;
default :
imagepng($this->src_im);
}
}
/**
* 存储图像
*/
function save($file){
switch ($this->type){
case 1:
imagegif($this->src_im,$file);
break;
case 2:
imagejpeg($this->src_im,$file);
break;
default :
imagepng($this->src_im,$file);
}
}
/**
* 清理
*/
function clean(){
imagedestroy($this->water_im);
imagedestroy($this->src_im);
}
/**
* 将十六进制颜色转为RGB
* @param type $hexColor
* @return array
*/
function hex2rgb($hexColor) {
$color = substr($hexColor,1);
if (strlen($color) > 3) {
$rgb = array(
'r' => hexdec(substr($color, 0, 2)),
'g' => hexdec(substr($color, 2, 2)),
'b' => hexdec(substr($color, 4, 2))
);
} else {
$color = $hexColor;
$r = substr($color, 0, 1) . substr($color, 0, 1);
$g = substr($color, 1, 1) . substr($color, 1, 1);
$b = substr($color, 2, 1) . substr($color, 2, 1);
$rgb = array(
'r' => hexdec($r),
'g' => hexdec($g),
'b' => hexdec($b)
);
}
return $rgb;
}
function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct){
$opacity=$pct;
// getting the watermark width
$w = imagesx($src_im);
// getting the watermark height
$h = imagesy($src_im);
// creating a cut resource
$cut = imagecreatetruecolor($src_w, $src_h);
// copying that section of the background to the cut
imagecopy($cut, $dst_im, 0, 0, $dst_x, $dst_y, $src_w, $src_h);
// inverting the opacity
$opacity = 100 - $opacity;
// placing the watermark now
imagecopy($cut, $src_im, 0, 0, $src_x, $src_y, $src_w, $src_h);
imagecopymerge($dst_im, $cut, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $opacity);
}
/**
* 重设图片大小
*
* @param type $maxwidth
*/
function resize($maxwidth=600){
$im = $this->src_im;
$width = imagesx($im);
$height = imagesy($im);
if($maxwidth && $width > $maxwidth){
$ratio = $maxwidth/$width;
$this->im_src_width = $width * $ratio;
$this->im_src_height = $height * $ratio;
if(function_exists("imagecopyresampled")){
$newim = imagecreatetruecolor($this->im_src_width , $this->im_src_height);
if(3 === $this->type){
imagealphablending($newim, false);
imagesavealpha($newim, true);
}
imagecopyresampled($newim, $im, 0, 0, 0, 0, $this->im_src_width , $this->im_src_height, $width, $height);
}else{
$newim = imagecreate($this->im_src_width , $this->im_src_height);
if(3 === $this->type){
imagealphablending($newim, false);
imagesavealpha($newim, true);
}
imagecopyresized($newim, $im, 0, 0, 0, 0, $this->im_src_width , $this->im_src_height, $width, $height);
}
$this->src_im = $newim;
}
}
}
?>

BIN
Watermark/lh.ttf Normal file

Binary file not shown.